力扣解题-58. 最后一个单词的长度

4 阅读6分钟

力扣解题-58. 最后一个单词的长度

给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。

单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。

示例 1: 输入:s = "Hello World" 输出:5 解释:最后一个单词是“World”,长度为 5。

示例 2: 输入:s = " fly me to the moon " 输出:4 解释:最后一个单词是“moon”,长度为 4。

示例 3: 输入:s = "luffy is still joyboy" 输出:6 解释:最后一个单词是长度为 6 的“joyboy”。

提示: 1 <= s.length <= 104 s 仅有英文字母和空格 ' ' 组成 s 中至少存在一个单词

Related Topics 字符串


第一次解答

解题思路

核心方法:首尾去空格 + 找最后一个空格位置,利用字符串内置方法快速处理空格问题,通过“最后一个空格的位置”计算最后一个单词的长度,逻辑简洁且性能拉满,时间复杂度O(n)、空间复杂度O(n)(去空格生成新字符串)。

核心逻辑拆解(通俗版)

要找最后一个单词的长度,核心是先消除干扰的首尾空格,再定位最后一个单词的起始位置:

  1. 字符串首尾的空格是无效的(比如示例2中开头的3个空格、结尾的2个空格),先去掉这些空格;
  2. 去掉空格后,字符串中最后一个空格的位置,就是“最后一个单词”的前一个位置;
  3. 用字符串总长度减去“最后一个空格的下标 + 1”,就是最后一个单词的长度(如果没有空格,说明整个字符串是一个单词,长度就是字符串长度)。
具体步骤
  1. 去除首尾空格:调用s.strip()方法(Java 11+支持),去除字符串开头和结尾的所有空格,得到无首尾冗余空格的新字符串(比如示例2处理后变为"fly me to the moon");
  2. 找最后一个空格的位置:调用s.lastIndexOf(" "),返回字符串中最后一个空格的下标(示例2处理后最后一个空格下标是"fly me to the "的最后一个位置,即14);
  3. 计算最后一个单词长度
    • 若存在最后一个空格(返回值≠-1):长度 = 处理后字符串长度 - 最后一个空格下标 - 1;
    • 若不存在空格(返回值=-1):长度 = 处理后字符串长度(整个字符串是一个单词);
  4. 返回结果:直接返回计算出的长度。
性能说明
  • 时间复杂度:O(n)(strip()lastIndexOf()均为线性遍历字符串,总操作数为O(n)),耗时0ms击败100%用户;
  • 空间复杂度:O(n)(strip()会生成新字符串,占用与原字符串等长的空间);
  • 优势:利用Java内置方法简化逻辑,代码行数少、可读性高,是工程中最常用的简洁解法;
  • 内存表现:42.3MB击败70.20%用户,是因为strip()生成新字符串的内存开销,属于该思路下的正常表现。
   public int lengthOfLastWord(String s) {
        //同时去掉首位空格,也可以使用s.stripTrailing(),去掉尾部空格
        s=s.strip();
        int index=s.lastIndexOf(" ");
        return s.length()-index-1;
    }

示例解答

解题思路

解法1:反向遍历法(空间最优解)

核心方法:从字符串末尾反向遍历,先跳过尾部所有空格,再统计最后一个单词的字符数,无需生成新字符串,空间复杂度O(1),是本题的最优解。

核心逻辑拆解(通俗版)

反向遍历的核心是“先避空,再计数”:

  1. 从字符串最后一个字符开始,先跳过所有尾部空格(比如示例2末尾的2个空格),找到最后一个单词的最后一个字符;
  2. 从该字符开始继续向前遍历,统计字符数,直到遇到空格或字符串开头;
  3. 统计的字符数就是最后一个单词的长度。
具体步骤(以示例2 s = " fly me to the moon "为例)
  1. 初始化两个变量:len = 0(统计单词长度)、i = s.length() - 1(从最后一个字符开始遍历);
  2. 跳过尾部空格:i从24(最后一个空格)→23(空格)→22(n),停止跳过;
  3. 统计单词字符:i=22(n)→len=1;i=21(o)→len=2;i=20(o)→len=3;i=19(m)→len=4;i=18(空格),停止统计;
  4. 返回len=4。
代码实现
public int lengthOfLastWord(String s) {
    int len = 0;
    int i = s.length() - 1;
    
    // 第一步:跳过尾部所有空格
    while (i >= 0 && s.charAt(i) == ' ') {
        i--;
    }
    
    // 第二步:统计最后一个单词的字符数
    while (i >= 0 && s.charAt(i) != ' ') {
        len++;
        i--;
    }
    
    return len;
}
性能优势
  • 时间复杂度:O(n)(最坏情况遍历整个字符串,实际通常只遍历尾部一小段);
  • 空间复杂度:O(1)(仅使用3个临时变量,无新字符串生成),内存开销比第一次解答更低;
  • 兼容性更好:无需依赖Java 11+的strip()方法,适配所有Java版本。
解法2:分割字符串法(易理解但效率略低)

核心方法:按空格分割字符串,过滤空字符串后取最后一个元素的长度,逻辑最直观,但分割会生成字符串数组,空间复杂度O(n)。

代码实现
public int lengthOfLastWord(String s) {
    // 按一个或多个空格分割,过滤空字符串
    String[] words = s.split("\\s+");
    // 取最后一个单词的长度
    return words[words.length - 1].length();
}
性能说明
  • 时间复杂度:O(n)(分割字符串需遍历整个字符串);
  • 空间复杂度:O(n)(分割生成的字符串数组占用空间);
  • 优势:逻辑极简,新手易理解,适合快速编写代码;
  • 劣势:正则表达式分割(\\s+)的常数开销略高,性能不如前两种解法。

总结

  1. 第一次解答(去空格+找最后空格):逻辑简洁,利用内置方法快速实现,空间O(n),适合工程快速开发;
  2. 反向遍历法(最优解):空间O(1),无额外内存开销,性能最优,适配所有Java版本;
  3. 分割字符串法:逻辑最直观,但正则分割有额外开销,适合理解思路而非追求性能;
  4. 关键技巧:处理“最后一个单词”类问题,优先考虑反向遍历,可避免处理头部冗余数据,且空间开销最小。