LC 151. 反转字符串中的单词
1. 问题描述
给你一个字符串 s,请你反转字符串中单词的顺序。
单词是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的单词分隔开。
返回单词顺序颠倒且单词之间用单个空格连接的结果字符串。
注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
示例 1: 输入:s = "the sky is blue" 输出:"blue is sky the" 示例 2: 输入:s = " hello world " 输出:"world hello" 解释:反转后的字符串中不能存在前导空格和尾随空格。 示例 3: 输入:s = "a good example" 输出:"example good a" 解释:如果两个单词间有多余的空格,反转后的字符串需要将单词间的空格减少到仅有一个。
提示:
1 <= s.length <= 104
- s 包含英文大小写字母、数字和空格
' '
- s 中 至少存在一个单词
进阶:如果字符串在你使用的编程语言中是一种可变数据类型,请尝试使用 O(1) 额外空间复杂度的原地解法。
2. 题解
方法一、使用语言特性
很多语言对字符串提供了 split(拆分),reverse(翻转)和 join(连接)等方法,因此可以简单的调用内置的 API 完成操作:
- 使用 split 将字符串按空格分割成字符串数组;
- 使用 reverse 将字符串数组进行反转;
- 使用 join 方法将字符串数组拼成一个字符串。
注意各函数的调用方法
class Solution { public String reverseWords(String s) { // 除去开头和末尾的空白字符 s = s.trim(); // 正则匹配连续的空白字符作为分隔符分割 List<String> wordList = Arrays.asList(s.split("\\s+")); //将数组转为集合,以方便调用reverse Collections.reverse(wordList); return String.join(" ", wordList); } }
复杂度分析
-
时间复杂度:O(n),其中 n 为输入字符串的长度。
-
空间复杂度:O(n),用来存储字符串分割之后的结果。
方法二、自行编写对应的函数
对于字符串不可变的语言,首先得把字符串转化成其他可变的数据结构,同时还需要在转化的过程中去除空格。

class Solution { public String reverseWords(String s) { StringBuilder sb = trimSpaces(s); // 翻转字符串 reverse(sb, 0, sb.length() - 1); // 翻转每个单词 reverseEachWord(sb); return sb.toString(); } public StringBuilder trimSpaces(String s) { int left = 0, right = s.length() - 1; // 去掉字符串开头的空白字符 while (left <= right && s.charAt(left) == ' ') { ++left; } // 去掉字符串末尾的空白字符 while (left <= right && s.charAt(right) == ' ') { --right; } // 将字符串间多余的空白字符去除 StringBuilder sb = new StringBuilder(); while (left <= right) { char c = s.charAt(left); if (c != ' ') { sb.append(c); } else if (sb.charAt(sb.length() - 1) != ' ') { // 当 c == ' ',且 sb 结尾没有被空白字符填充时 sb.append(c); } ++left; } return sb; } public void reverse(StringBuilder sb, int left, int right) { while (left < right) { char tmp = sb.charAt(left); sb.setCharAt(left++, sb.charAt(right)); //setCharAt函数接口 sb.setCharAt(right--, tmp); } } public void reverseEachWord(StringBuilder sb) { int n = sb.length(); int start = 0, end = 0; while (start < n) { // 循环至单词的末尾 while (end < n && sb.charAt(end) != ' ') { ++end; } // 翻转单词 reverse(sb, start, end - 1); // 更新start,去找下一个单词 start = end + 1; ++end; } } }
复杂度分析
-
时间复杂度:O(n),其中 n 为输入字符串的长度。
-
空间复杂度:Java O(n) 的空间来存储字符串。
方法三、双端队列
由于双端队列支持从队列头部插入的方法,因此可以沿着字符串一个一个单词处理,然后将单词压入队列的头部,再将队列转成字符串即可。
class Solution { public String reverseWords(String s) { int left = 0, right = s.length() - 1; // 去掉字符串开头的空白字符 while (left <= right && s.charAt(left) == ' ') { ++left; } // 去掉字符串末尾的空白字符 while (left <= right && s.charAt(right) == ' ') { --right; } Deque<String> d = new ArrayDeque<String>(); StringBuilder word = new StringBuilder(); while (left <= right) { char c = s.charAt(left); if ((word.length() != 0) && (c == ' ')) { // 将单词 push 到队列的头部 d.offerFirst(word.toString()); word.setLength(0); } else if (c != ' ') { word.append(c); } ++left; } d.offerFirst(word.toString()); return String.join(" ", d); } }
复杂度分析
-
时间复杂度:O(n),其中 n 为输入字符串的长度。
-
空间复杂度:OO(n),双端队列存储单词需要 O(n) 的空间。
整理于 LeetCode 官方题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)