LeetCode 151:双指针法反转字符串单词详解
发布时间:2026/10/15 11:53:05 锦皓数字建站

1. 题目背景与核心需求解析这道LeetCode 151题反转字符串中的单词是字符串处理类问题的经典代表也是大厂面试中的高频考题。题目要求我们将给定字符串中的单词顺序进行反转同时需要处理多余空格的问题。举个例子输入the sky is blue 输出blue is sky the看似简单的需求背后隐藏着几个关键考察点字符串中可能存在前导/尾随空格单词间可能存在多个连续空格需要保证反转后的字符串单词间只保留单个空格不能使用语言内置的split()等高级函数面试时常见限制1.1 大厂面试的深层考察意图这道题在大厂机考中频繁出现主要考察以下几个维度对字符串基本操作的掌握程度遍历、截取、拼接等边界条件的处理能力空格处理、空字符串等空间复杂度的控制意识是否使用O(1)空间解法代码实现的简洁性与可读性在实际面试场景中面试官往往会追加限制条件比如 请在不使用额外空间的情况下完成 请用O(n)时间复杂度和O(1)空间复杂度实现 这些变体都需要我们对基础解法有深入理解才能应对。2. 基础解法双端队列双指针法详解2.1 算法思路拆解双端队列双指针法是解决这类字符串反转问题的经典套路其核心思想可以分解为以下步骤预处理阶段使用双指针跳过字符串首尾的空格单词提取阶段使用快慢指针配合识别并提取完整单词存储阶段将提取的单词按顺序存入双端队列的头部拼接阶段将队列中的单词用空格连接输出这种方法的优势在于时间复杂度O(n)只需一次完整遍历空间复杂度O(n)需要额外存储单词符合大多数面试要求逻辑清晰各步骤职责明确易于理解和实现2.2 完整代码实现与逐行解析from collections import deque def reverseWords(s: str) - str: left, right 0, len(s) - 1 # 去除开头空格 while left right and s[left] : left 1 # 去除末尾空格 while left right and s[right] : right - 1 dq deque() word [] # 提取单词 while left right: if s[left] ! : word.append(s[left]) else: if word: # 遇到空格且word不为空表示一个单词结束 dq.appendleft(.join(word)) word [] left 1 # 添加最后一个单词 dq.appendleft(.join(word)) return .join(dq)关键代码解析left和right指针初始定位到字符串首尾非空格位置word列表动态收集当前单词的字符遇到空格时将完整单词添加到双端队列头部实现反转最后处理末尾单词因为末尾没有触发空格的条件2.3 复杂度分析与优化空间时间复杂度O(n)每个字符最多被访问两次一次跳过空格一次处理单词双端队列的appendleft操作是O(1)空间复杂度O(n)存储所有单词需要额外空间单词列表和双端队列的空间消耗优化方向如果允许使用split()代码可以更简洁但面试常限制使用可以使用字符串拼接代替双端队列但时间复杂度可能上升更高级的O(1)空间解法需要原地修改字符串Python中字符串不可变较难实现3. 核心技巧与避坑指南3.1 双指针使用的五个关键细节指针移动顺序必须先移动右指针跳过尾部空格再处理左指针边界条件检查while循环必须包含left right条件防止越界单词结束判断遇到空格且word不为空时才视为单词结束最后一个单词处理循环结束后必须单独处理最后一个单词连续空格处理通过if word条件过滤掉连续空格产生的影响3.2 面试中常见的三个实现陷阱忘记处理首尾空格直接开始处理会导致结果包含多余空格错误示例输入 hello world 输出world hello连续空格处理不当可能导致结果中出现空单词错误示例输入a b输出b a最后一个单词遗漏因为末尾没有触发空格条件而忘记添加错误示例输入hello world输出world3.3 调试与验证方法建议使用以下测试用例验证代码正确性测试用例 1. 常规情况the sky is blue → blue is sky the 2. 前后空格 hello world → world hello 3. 连续空格a good example → example good a 4. 单单词hello → hello 5. 全空格 → 在IDE中调试时可以在指针移动处打印left/right值在添加单词时打印当前双端队列状态使用断点观察word列表的变化过程4. 解法变体与进阶思路4.1 不使用双端队列的替代方案如果面试中限制使用双端队列可以用列表反转代替def reverseWords(s: str) - str: # ... 前处理相同 ... words [] word [] while left right: if s[left] ! : word.append(s[left]) else: if word: words.append(.join(word)) word [] left 1 words.append(.join(word)) return .join(reversed(words))4.2 O(1)空间复杂度的挑战对于支持字符串可变性的语言如C可以实现真正的O(1)空间解法先反转整个字符串再反转每个单词最后处理多余空格Python中由于字符串不可变难以实现真正的O(1)空间但可以模拟def reverseWords(s: str) - str: # 转换为列表模拟可变字符串 s list(s) n len(s) # 反转整个字符串 def reverse(l, r): while l r: s[l], s[r] s[r], s[l] l 1 r - 1 # 反转每个单词 def reverse_each_word(): start end 0 while start n: # 跳过空格 while start n and s[start] : start 1 end start # 定位单词结尾 while end n and s[end] ! : end 1 reverse(start, end - 1) start end # 去除多余空格 def trim_spaces(): slow fast 0 # 跳过开头空格 while fast n and s[fast] : fast 1 # 处理中间部分 while fast n: if s[fast] ! : s[slow] s[fast] slow 1 fast 1 else: # 保留一个空格 s[slow] slow 1 fast 1 # 跳过后续空格 while fast n and s[fast] : fast 1 # 处理末尾可能多余的空格 return .join(s[:slow-1] if slow 0 and s[slow-1] else s[:slow]) reverse(0, n-1) reverse_each_word() return trim_spaces()4.3 实际工程中的优化考量在真实项目场景中我们还需要考虑多语言支持处理Unicode字符时的特殊考虑超大字符串处理内存受限时的流式处理方案性能优化对于频繁调用的场景可以预编译正则表达式API设计是否提供原地修改和返回新字符串两种选项5. 同类问题拓展与练习建议5.1 推荐练习的变体题目LeetCode 186. 反转字符串中的单词 II要求原地修改LeetCode 557. 反转字符串中的单词 III反转每个单词但保持顺序LeetCode 344. 反转字符串更基础的反转问题LeetCode 541. 反转字符串 II每隔2k字符反转前k个5.2 字符串处理通用技巧总结双指针法适用于大多数遍历条件处理场景滑动窗口解决子串/子数组相关问题递归回溯处理组合类字符串问题KMP算法高效解决字符串匹配问题字典树(Trie)处理前缀相关查询5.3 大厂面试准备建议至少掌握3种不同的实现方法能够分析各方法的时间/空间复杂度准备测试用例覆盖各种边界条件练习在白板/记事本上手写代码模拟面试时限制使用特定函数如不用split()我在实际面试辅导中发现很多同学卡在这道题不是因为算法不会而是输在细节处理上。建议每次写完代码后用这几个问题自检是否处理了首尾空格连续空格情况下是否正确输出单单词和全空格的特殊情况能否处理代码是否清晰易读变量命名是否合理
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。