反转字符串中的单词
字符串 双指针题目描述
给定一个字符串 s,请你反转字符串中 单词 的顺序。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
要求:
- 返回一个翻转后的字符串,单词之间只用一个空格隔开。
- 输入字符串
s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,不应包含任何额外的空格。
思路分析
处理字符串翻转主要有两种常见的方式:
-
借助内置方法(分割+反转+拼接): 利用语言原生的字符串处理函数,首先去除首尾空格,再按空格把字符串拆分成由单词组成的数组,接着反转这个数组,最后再把数组用单一空格重新拼接。这种方式代码最简短、开发效率最高。
-
纯享版:双指针倒序遍历提取: 不依赖高级 API(如
split、正则等),直接从字符串末尾开始倒序遍历字符串自身。利用双指针(left和right)框定每个单词的边界,然后将其依次截取下来存放在新数组里,最后统一拼接返回结果。这对于理解指针移动和考察原生底层逻辑非常有帮助。
算法步骤 (双指针解法)
- 先将字符串去除首部和尾部的空格(或者遍历时忽略它们)。
- 从原字符串尾部向头部遍历,初始时两个指针
left和right都位于结尾。 - 当遇到非空格字符时,
left持续向左移动,直至遇到第一个空格。这代表已经找到了一个单词的左边界。 - 将子串
[left + 1, right]截取出来存入结果中。 - 接着
left继续向左移动,跳过所有的相邻空格,直到遇到下一个单词的尾部,将right更新到此时left的位置。 - 不断重复上述两步处理,直到遍历完所有字符,最后把收集好的单词拼接起来。
示例代码
复杂度分析
- 时间复杂度:
O(n),其中n是字符串的长度。原生方法需要扫描拆分并反转;双指针解法从后往前遍历字符串一次。无论是直接切割还是逐字符寻找单词,处理代价都正比于字符串尺寸。 - 空间复杂度:
O(n)。JavaScript 中字符串是不可变的类型,所以对于双指针解法我们也需要借助一个数组来接收每个新截取出的单词以重组结果,数组以及最终拼接成的字符串都会消耗O(n)的额外空间。
示例演示
以 s = " hello world " 为例,双指针处理过程如下:
- 初始剔除多余部分(如果有,或者跳过首尾空格)可以先将它当成
"hello world"处理。 - 初始时,
right和left都在末尾字母'd'(索引 10) 处。 - 循环倒序寻找:
left一路向左,从'd'、'l'、'r'、'o'、'w'一直减到' '(索引 5)。此时,就确定了一个单词。 - 我们把子串(从
left + 1为起始索引 6 一直到right为 10)即"world"保存到结果集合中。 - 然后继续移动:
left跳过当前的空格,停在字符'o'(索引 4) 上。这时候把right对齐到left,并重新开始寻找下一个单词的首字母。 left再度探索直到索引-1,由于越界跳出寻找单词内部字母的循环。把left + 1(索引 0) 到right(索引 4) 的单词"hello"追加存入。- 此时结果集合中已经保存了
["world", "hello"]。 - 最终合并它们为
"world hello"。