LeetCode 58. 最后一个单词的长度:两种解法深度剖析

0 阅读5分钟

在 LeetCode 简单题中,58 题“最后一个单词的长度”看似基础,却能很好地考察对字符串处理的细节把控和算法效率的思考。题目要求我们在一个由单词和空格组成的字符串中,返回最后一个纯字母单词的长度(单词不含空格,且被若干空格分隔)。本文将带来两种主流解法,从思路、代码到优劣对比,帮你彻底吃透这道题。

题目回顾

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

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

示例 1:输入 s = "Hello World",输出 5(最后一个单词为 "World");

示例 2:输入 s = " fly me to the moon ",输出 4(最后一个单词为 "moon");

示例 3:输入 s = "luffy is still joyboy",输出 6(最后一个单词为 "joyboy")。

解法一:正则分割 + 数组取值(简洁高效款)

思路分析

这种解法的核心是利用字符串处理方法和正则表达式,将混乱的字符串转化为干净的单词数组,再直接取最后一个单词的长度。核心步骤分为两步:

  1. trim() 方法去除字符串首尾的空格,避免首尾空格对分割结果的干扰;

  2. 用正则表达式 /\s+/ 分割字符串,该正则能匹配一个或多个连续空格,完美解决“多个空格分隔单词”的问题,得到仅包含有效单词的数组;

  3. 取数组最后一个元素,返回其长度即可。

代码实现(TypeScript)


function lengthOfLastWord_1(s: string): number {
  // 去除首尾空格后,按一个或多个空格分割为单词数组
  const sArr: string[] = s.trim().split(/\s+/);
  // 返回最后一个单词的长度
  return sArr[sArr.length - 1].length;
};

关键细节说明

  1. 为什么不用 split(' ')?直接用单个空格分割会导致连续空格产生空字符串(如示例 2 分割后会出现 ["", "fly", "me", "", "", "to", ...]),后续还要过滤空字符串,繁琐且低效;

  2. trim() 的作用?若不使用 trim(),字符串开头的空格会被 /\s+/ 匹配,分割后数组第一个元素为空字符串(如示例 2 不 trim() 会得到 ["", "fly", "me", ...]),虽不影响取最后一个元素,但会多一步无效分割;

  3. 时间复杂度:trim()split() 均为 O(n)(n 为字符串长度),整体时间复杂度 O(n);空间复杂度 O(m)(m 为单词个数),因为需要存储分割后的单词数组。

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

思路分析

解法一虽简洁,但额外占用了数组空间。如果追求空间最优,可采用反向遍历的思路:从字符串末尾开始,先跳过所有末尾空格,找到最后一个单词的结尾,再继续反向遍历统计单词长度,直到遇到空格或遍历结束。核心步骤:

  1. 定义索引 index 指向字符串最后一个字符(s.length - 1);

  2. 反向遍历跳过末尾空格:当index >= 0 且当前字符是空格时,index--

  3. 统计最后一个单词长度:当 index >= 0 且当前字符不是空格时,计数器 res++index--

  4. 返回计数器 res,即为最后一个单词的长度。

代码实现(TypeScript)


function lengthOfLastWord_2(s: string): number {
  let index = s.length - 1;
  // 跳过末尾的所有空格
  while (s[index] === ' ' && index >= 0) {
    index--;
  }
  let res = 0;
  // 统计最后一个单词的长度
  while (index >= 0 && s[index] !== ' ') {
    res++;
    index--;
  }
  return res;
};

关键细节说明

  1. 边界条件处理:index >= 0 是避免遍历越界(当字符串全为空格时,第一个循环会将 index 减至 -1,第二个循环不执行,返回 0,符合题意);

  2. 空间优势:全程仅使用两个变量(indexres),空间复杂度为 O(1);

  3. 时间复杂度:最坏情况下需遍历整个字符串(如字符串无空格),时间复杂度仍为 O(n),但无额外空间开销。

两种解法对比与适用场景

解法时间复杂度空间复杂度优点缺点适用场景
正则分割 + 数组取值O(n)O(m)代码简洁、易理解,开发效率高额外占用数组空间日常开发、算法题快速解题,对空间要求不高的场景
反向遍历O(n)O(1)空间最优,无额外开销代码稍长,需处理边界条件空间敏感场景,如大规模字符串处理、面试中追求最优空间复杂度

常见坑点提醒

  • 忽略全空格字符串:如输入 " ",此时无有效单词,应返回 0,两种解法均能正确处理;

  • 多个连续空格分隔:解法一靠 /\s+/ 解决,解法二靠反向跳空处理,均需避免将连续空格计入单词长度;

  • 单词仅一个的情况:如输入 "Hello"" Hello",两种解法均能正确返回 5。

总结

LeetCode 58 题虽为简单题,但两种解法对应了不同的优化方向:解法一以空间换简洁,适合快速落地;解法二以时间换空间,适合追求极致性能。在面试中,若能同时给出两种解法并分析其优劣,会更受面试官青睐。

其实字符串处理类题目核心在于对细节的把控,无论是正则的灵活运用,还是遍历方向的选择,都需要结合场景权衡。希望本文能帮你掌握这道题的本质,在后续同类题目中举一反三。