题目描述

✅ 58. 最后一个单词的长度

image-20260928224332808

image-20260928224332809

题意分析

字符串只由英文字母和空格组成,单词是一段连续的非空字母,返回最后一个单词的字母数量。字符串开头、末尾或词间都可能有多个空格,题目保证至少存在一个单词。

末尾的空格不是单词的一部分;最后一个单词也可能就是整个字符串。需要的是长度,不需要返回单词文本或它的起止位置。

解法:从后向前扫描

核心思路

[!blue]

从右侧开始更容易直接找到最后一个单词,不必拆分并保存前面所有单词。先跳过尾随空格,直到指针停在最后一个单词的最后一个字母上。

接下来进入计数阶段,只要当前位置仍是非空格字符,就把长度加一并向左移动。此时每次经过的字母都与已经计数的部分相邻,仍属于同一个最后单词;遇到空格,就到达了它与前一个单词的分界,可以立即结束。

若一直没有遇到空格而到达字符串开头,说明最后单词从下标零开始;指针继续减到负数后也应停止。两个循环都先检查下标非负,再读取字符,利用短路判断避免越界。

跳过尾空格和统计字母是两个不同阶段,不能把遇到的所有非空格字符一直累计,否则会把更早的单词也算进去。题目只包含英文字母,因此 Go 按字节计数与这里要求的字母数一致。

解题步骤

  1. 将下标放在字符串最后一个字符。
  2. 向左跳过所有尾随空格。
  3. 从零开始统计接下来连续的非空格字符,并同步向左移动。
  4. 遇到词间空格或越过开头时停止,返回长度。

代码实现

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. 字符串中的单词数 简单 同样区分单词与分隔空格,原题统计全部非空段,本题只计算最后一段长度。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2025/23908408
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!