LeetCode 151. 反转字符串中的单词:两种解法深度剖析

在字符串处理类算法题中,LeetCode 151 题"反转字符串中的单词"是一道经典入门题。它不仅考察对字符串基本操作的掌握,还能延伸出"API 调用"与"手动模拟"两种核心解题思路,适合不同场景下的应用。本文将详细拆解题目要求,深入分析两种解法的原理、代码细节及优劣差异,帮助大家彻底掌握这道题。

一、题目核心要求

题目给出一个字符串 s,要求反转其中单词的顺序,同时需满足以下约束条件:

  • 单词定义:由非空格字符组成的连续字符串,单词间用至少一个空格分隔;

  • 输入特性:可能存在前导空格、尾随空格、单词间多个空格;

  • 输出要求:单词顺序颠倒,单词间仅用单个空格分隔,无任何额外空格。

示例:输入 " hello world ",输出 "world hello";输入 "a good example",输出 "example good a"

二、解法一:API 快速实现(简洁高效)

1. 解题思路

利用 JavaScript/TypeScript 内置字符串、数组 API,三步完成需求:

  1. trim():去除字符串首尾的空格,解决前导、尾随空格问题;

  2. split(/\s+/):以一个或多个空格为分隔符拆分字符串,得到无空元素的单词数组(解决单词间多空格问题);

  3. reverse().join(' '):反转单词数组,再用单个空格连接,得到最终结果。

2. 代码实现(TypeScript)

typescript 复制代码
function reverseWords_1(s: string): string {
  const sArr = s.trim().split(/\s+/);
  return sArr.reverse().join(' ');
};

3. 解法分析

优点 :代码极度简洁,开发效率高,内置 API 经过优化,在大多数场景下性能足够优秀。拆分时使用正则表达式 /\s+/ 精准匹配多空格,避免拆分后出现空数组元素,无需额外过滤。

缺点:过度依赖 API,若在面试中仅给出此解法,可能无法体现对字符串底层操作的理解;正则表达式的执行成本略高于纯循环(但在常规字符串长度下可忽略)。

时间复杂度 :O(n),其中 n 为字符串长度。trim()split()reverse()join() 均为线性时间操作。

空间复杂度:O(n),拆分后得到的单词数组需占用 O(n) 额外空间。

二、解法二:手动模拟(底层逻辑实现)

1. 解题思路

不依赖复杂 API,通过反向遍历字符串手动拼接单词,全程仅维护两个变量(结果字符串、临时单词字符串),核心逻辑:

  1. 从字符串末尾开始反向遍历,逐个读取字符;

  2. 遇到非空格字符时,拼接到临时单词字符串的头部(因反向遍历,需保证单词内部顺序正确);

  3. 遇到空格且临时单词非空时,说明已完整读取一个单词,将其拼接到结果字符串后,重置临时单词;

  4. 遍历结束后,若临时单词非空(说明第一个单词未拼接),补充到结果字符串,最后去除首尾可能存在的空格(仅尾部可能有多余空格)。

2. 代码实现(TypeScript)

typescript 复制代码
function reverseWords_2(s: string): string {
  const sL = s.length;
  let res = '';
  let word = '';
  for (let i = sL - 1; i >= 0; i--) {
    const char = s[i];
    if (char !== ' ') {
      // 非空格字符,拼接到单词头部(维持单词原顺序)
      word = char + word;
    } else if (word) {
      // 遇到空格且有已拼接单词,存入结果并重置单词
      res += word + ' ';
      word = '';
    }
  }
  // 补充最后一个单词(遍历结束时word可能非空)
  if (word) {
    res += word;
  }
  return res.trim();
};

3. 关键细节说明

  • 反向遍历的优势:无需先拆分所有单词再反转,可边遍历边构建结果,逻辑更直观;

  • 单词拼接方式:word = char + word 而非 word += char,因为反向遍历读取单词的顺序是"末尾→开头",拼接到头部才能还原单词原顺序;

  • 空格判断条件:else if (word) 避免了多个空格连续出现时重复拼接空内容,同时跳过字符串开头(反向遍历的末尾)的空格;

  • 遍历后补充单词:因字符串开头(反向遍历的末尾)无空格,最后一个单词无法通过"遇到空格"触发拼接,需单独处理。

4. 解法分析

优点:完全体现底层逻辑,适合面试场景,能展示对字符串操作的深刻理解;无正则表达式开销,空间利用率更优(可视为 O(1) 额外空间,仅用两个变量,忽略结果存储的空间)。

缺点:代码行数较多,需注意边界条件(如单个单词、全空格字符串),容易出现逻辑漏洞。

时间复杂度:O(n),仅遍历一次字符串,所有操作均为常数时间。

空间复杂度:O(n),结果字符串和临时单词字符串的总长度不超过原字符串长度。

三、两种解法对比与适用场景

维度 API 解法 手动模拟解法
代码简洁度 极高,一行核心逻辑 中等,需处理边界条件
底层理解体现 弱,依赖内置 API 强,手动实现核心逻辑
性能 优秀,API 优化充分 略优,无正则开销
适用场景 日常开发、快速迭代 面试、底层逻辑验证

四、边界案例测试

无论哪种解法,都需覆盖以下边界案例,确保正确性:

  1. 字符串仅含一个单词:输入 "hello",输出 "hello"

  2. 字符串全为空格:输入 " ",输出 ""

  3. 单词间多个空格:输入 "a b c ",输出 "c b a"

  4. 字符串长度为 1:输入 "a",输出 "a",输入 " ",输出 ""

五、总结

LeetCode 151 题的两种解法各有侧重:API 解法胜在简洁高效,适合实际开发中的快速实现;手动模拟解法胜在底层逻辑清晰,是面试中的加分项。

核心考点在于"处理空格"与"反转单词顺序",无论哪种解法,都需明确:① 如何去除多余空格;② 如何保证单词内部顺序正确;③ 如何反转单词间的顺序。掌握这两个解法,既能应对日常开发需求,也能从容应对面试中的深度提问。

相关推荐
芜湖xin2 小时前
【题解-Acwing】AcWing 5579. 增加模数(TLE)
算法·快速幂
清酒难咽2 小时前
算法案例之分治法
c++·经验分享·算法
wen__xvn2 小时前
代码随想录算法训练营DAY25第七章 回溯算法 part04
算法·leetcode·深度优先
亲爱的非洲野猪2 小时前
动态规划进阶:序列DP深度解析
算法·动态规划
yinmaisoft2 小时前
JNPF 表单模板实操:高效复用表单设计指南
前端·javascript·html
37方寸2 小时前
前端基础知识(JavaScript)
开发语言·前端·javascript
不染尘.2 小时前
双指针算法
算法
2501_901147833 小时前
题解:有效的正方形
算法·面试·职场和发展·求职招聘
你撅嘴真丑3 小时前
习题与总结
算法