LeetCode 58. 最后一个单词的长度
题目描述


题意分析
字符串只由英文字母和空格组成,单词是一段连续的非空字母,返回最后一个单词的字母数量。字符串开头、末尾或词间都可能有多个空格,题目保证至少存在一个单词。
末尾的空格不是单词的一部分;最后一个单词也可能就是整个字符串。需要的是长度,不需要返回单词文本或它的起止位置。
解法:从后向前扫描
核心思路
[!blue]
从右侧开始更容易直接找到最后一个单词,不必拆分并保存前面所有单词。先跳过尾随空格,直到指针停在最后一个单词的最后一个字母上。
接下来进入计数阶段,只要当前位置仍是非空格字符,就把长度加一并向左移动。此时每次经过的字母都与已经计数的部分相邻,仍属于同一个最后单词;遇到空格,就到达了它与前一个单词的分界,可以立即结束。
若一直没有遇到空格而到达字符串开头,说明最后单词从下标零开始;指针继续减到负数后也应停止。两个循环都先检查下标非负,再读取字符,利用短路判断避免越界。
跳过尾空格和统计字母是两个不同阶段,不能把遇到的所有非空格字符一直累计,否则会把更早的单词也算进去。题目只包含英文字母,因此 Go 按字节计数与这里要求的字母数一致。
解题步骤
- 将下标放在字符串最后一个字符。
- 向左跳过所有尾随空格。
- 从零开始统计接下来连续的非空格字符,并同步向左移动。
- 遇到词间空格或越过开头时停止,返回长度。
代码实现
class Solution {
// 末尾可能有空格,必须先从后往前跳过这些空格。
public int lengthOfLastWord(String s) {
int i = s.length() - 1;
while (i >= 0 && s.charAt(i) == ' ') {
i--;
}
// 尾空格已跳过,接下来只统计最后一个单词,仍先检查下标
int len = 0;
while (i >= 0 && s.charAt(i) != ' ') {
len++;
i--;
}
return len;
}
}
func lengthOfLastWord(s string) int {
// 末尾可能有空格,必须先从后往前跳过这些空格。
i := len(s) - 1
for i >= 0 && s[i] == ' ' {
i--
}
// 尾空格已跳过,接下来只统计最后一个单词,仍先检查下标
length := 0
for i >= 0 && s[i] != ' ' {
length++
i--
}
return length
}
复杂度分析
- 时间复杂度:若尾空格数为
t、最后单词长度为k,只需扫描这两部分及其边界,为 $O(t + k)$,最坏为 $O(n)$。- 空间复杂度:$O(1)$,只保存下标和长度,不创建单词数组或子串。
关键点总结
[!green]
- 先找到最后单词的右端,再向左数到它的左边界。
- 词间空格结束计数,尾随空格只负责跳过。
- 下标判断在字符读取之前,整个字符串只有一个单词时也能安全结束。
易错点总结
[!yellow]
- 未先跳过尾空格,就直接统计末尾连续字母,会错误得到零。
- 开始计数后遇到空格还继续向前寻找,会把前面的单词也计入。
- 把字符读取放在下标检查之前,会在向左越过开头时越界。
- 返回最终停止的下标而非累计长度,不能表示单词大小。
- 只跳过一个尾空格,无法处理连续多个尾随空格。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 151. 反转字符串中的单词 | 中等 | 同样要跳过多余空格并定位单词边界,原题处理全部单词,本题只从末尾找到最后一词。 |
| 434. 字符串中的单词数 | 简单 | 同样区分单词与分隔空格,原题统计全部非空段,本题只计算最后一段长度。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!