题目描述

✅ 434. 字符串中的单词数

image-20260929100659561

题意分析

这里的“单词”指一段连续的非空格字符,只由普通空格 ' ' 分隔,不要求内容都是字母。数字或标点只要没有被空格隔开,就仍属于同一段。

需要返回片段数量,不需要保存片段内容。因此无需实际切割字符串,只要识别每段开始的位置。

解法:一次扫描计数

核心思路

[!blue]

一个位置是片段开头,需要同时满足两个条件:当前字符不是空格;当前位置在串首,或者前一个字符是空格。后一个条件表示扫描刚从分隔区域进入了一段内容。

每个非空格片段的首字符都符合这个条件,而片段内部字符的前一位仍是非空格,不会再次计数。反过来,任何符合条件的位置都确实开始一个新片段。因此段首与片段一一对应,累计段首数量就是答案。

计数在开头就已完成,最后一段后面有没有空格都不会影响结果。连续空格和前后空格因为自身不满足“当前非空格”,也都不会多贡献计数。

解题步骤

  1. 初始化计数 answer = 0,从左到右扫描字符串。
  2. 若当前位置非空格,继续检查它是否位于串首,或前一个字符是否为空格。
  3. 满足条件就将计数加一,扫描结束后返回总数。

串首用 i == 0 单独覆盖,通过逻辑或的短路求值避免读取负下标。空串不进入循环,全空格字符串没有段首,两者都返回零。

代码实现

class Solution {
    public int countSegments(String s) {
        int answer = 0;

        for (int i = 0; i < s.length(); i++) {
            // 当前非空格且前面是分隔符或串首,才开始一个新片段。
            if (s.charAt(i) != ' ' && (i == 0 || s.charAt(i - 1) == ' ')) {
                answer++;
            }
        }

        return answer;
    }
}
func countSegments(s string) int {
    answer := 0
    for i := range s {
        // 当前非空格且前面是分隔符或串首,才开始一个新片段。
        if s[i] != ' ' && (i == 0 || s[i-1] == ' ') {
            answer++
        }
    }
    return answer
}

复杂度分析

  • 时间复杂度:$O(L+1)$,L 为字符串长度,一次扫描。
  • 空间复杂度:$O(1)$,不创建分割数组。

关键点总结

[!green]

  • 计数对象是段首,不是非空格字符本身。
  • 串首条件通过短路判断保护前驱访问。
  • 连续、前导和尾随空格都由同一条件处理。

易错点总结

[!yellow]

  • 空格数量加一:连续或前导空格会多算。
  • 每个非空格字符都加一:统计成字符数。
  • 只在空格处结算又不补末段:最后没有空格时漏计。
  • 把标点当成分隔符:改变了题目对片段的定义。

相似题目

题目 难度 关联与区别
58. 最后一个单词的长度 简单 同样识别空格分隔的非空单词段,原题只计算最后一段长度。
151. 反转字符串中的单词 中等 单词边界识别可复用,原题还把所有单词按逆序输出。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2022/44713967
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!