LeetCode 151:反转字符串中的单词,解题思路分享
Hey guys! 今天我们要聊的是 LeetCode 上的一道经典题目 —— 151. 反转字符串中的单词。这道题考察了我们对字符串处理的掌握程度,以及如何清晰地拆解问题、高效地解决问题。让我们一起深入探讨这道题的解法,提升我们的编程技能吧!
题目描述
首先,让我们来回顾一下题目内容。给定一个字符串 s
,你需要将字符串中的单词顺序颠倒过来。注意,字符串中可能包含前导空格、尾随空格以及单词之间的多个空格。你的任务是清理这些多余的空格,并返回一个单词顺序反转且单词之间只有一个空格的字符串。
例如:
-
输入:
"the sky is blue"
-
输出:
"blue is sky the"
-
输入:
" hello world "
-
输出:
"world hello"
-
输入:
"a good example"
-
输出:
"example good a"
这道题的核心在于如何处理字符串中的空格,以及如何高效地反转单词顺序。接下来,我们将一起探讨几种不同的解题思路。
解题思路
解决这道题,我们可以采用多种思路。这里我们主要探讨三种常见的方法:
- 使用编程语言自带的字符串处理函数
- 双指针法
- 手动实现字符串分割和反转
让我们逐一分析这些方法,看看它们的优缺点以及适用场景。
方法一:利用编程语言的字符串处理函数
许多编程语言都提供了强大的字符串处理函数,例如 Python 的 split()
和 join()
,Java 的 split()
和 StringJoiner
等。我们可以利用这些函数来简化我们的代码。
这种方法的思路很简单:
- 去除首尾空格: 首先,使用
trim()
函数去除字符串首尾的空格。 - 分割字符串: 使用
split()
函数将字符串分割成单词数组。注意,我们需要使用正则表达式"\s+"
来匹配一个或多个空格,这样可以处理单词之间的多个空格。 - 反转单词数组: 将单词数组反转。
- 拼接字符串: 使用
join()
函数将反转后的单词数组拼接成字符串,单词之间用一个空格分隔。
以 Java 为例,代码如下:
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class ReverseWords {
public String reverseWords(String s) {
// 1. 去除首尾空格
s = s.trim();
// 2. 分割字符串
List<String> wordList = Arrays.asList(s.split("\\s+"));
// 3. 反转单词数组
Collections.reverse(wordList);
// 4. 拼接字符串
return String.join(" ", wordList);
}
public static void main(String[] args) {
ReverseWords solution = new ReverseWords();
String s1 = "the sky is blue";
String s2 = " hello world ";
String s3 = "a good example";
System.out.println("\"" + s1 + "\" 反转后: \"" + solution.reverseWords(s1) + "\"");
System.out.println("\"" + s2 + "\" 反转后: \"" + solution.reverseWords(s2) + "\"");
System.out.println("\"" + s3 + "\" 反转后: \"" + solution.reverseWords(s3) + "\"");
}
}
这种方法的优点:
- 代码简洁易懂,逻辑清晰。
- 利用了编程语言提供的现成函数,效率较高。
这种方法的缺点:
- 可能会产生额外的空间开销,例如
split()
函数会创建一个新的字符串数组。 - 对于某些对空间复杂度要求极高的场景,可能不是最优解。
方法二:双指针法
双指针法是一种常用的算法技巧,可以用来解决许多字符串和数组相关的问题。对于这道题,我们也可以使用双指针法来实现原地反转。
思路如下:
- 去除多余空格: 首先,我们需要去除字符串中多余的空格,包括首尾空格和单词之间的多个空格。我们可以使用双指针法来实现原地去除空格。
- 反转整个字符串: 将整个字符串反转。
- 反转每个单词: 遍历字符串,找到每个单词的起始和结束位置,然后将单词反转。
以 Java 为例,代码如下:
public class ReverseWords {
public String reverseWords(String s) {
// 1. 去除多余空格
StringBuilder sb = removeSpace(s);
// 2. 反转整个字符串
reverseString(sb, 0, sb.length() - 1);
// 3. 反转每个单词
reverseEachWord(sb);
return sb.toString();
}
private StringBuilder removeSpace(String s) {
int start = 0;
int end = s.length() - 1;
// 去除首尾空格
while (s.charAt(start) == ' ') start++;
while (s.charAt(end) == ' ') end--;
StringBuilder sb = new StringBuilder();
while (start <= end) {
char c = s.charAt(start);
if (c != ' ' || sb.charAt(sb.length() - 1) != ' ') {
sb.append(c);
}
start++;
}
return sb;
}
private void reverseString(StringBuilder sb, int start, int end) {
while (start < end) {
char temp = sb.charAt(start);
sb.setCharAt(start, sb.charAt(end));
sb.setCharAt(end, temp);
start++;
end--;
}
}
private void reverseEachWord(StringBuilder sb) {
int start = 0;
int end = 1;
int n = sb.length();
while (start < n) {
while (end < n && sb.charAt(end) != ' ') {
end++;
}
reverseString(sb, start, end - 1);
start = end + 1;
end = start + 1;
}
}
public static void main(String[] args) {
ReverseWords solution = new ReverseWords();
String s1 = "the sky is blue";
String s2 = " hello world ";
String s3 = "a good example";
System.out.println("\"" + s1 + "\" 反转后: \"" + solution.reverseWords(s1) + "\"");
System.out.println("\"" + s2 + "\" 反转后: \"" + solution.reverseWords(s2) + "\"");
System.out.println("\"" + s3 + "\" 反转后: \"" + solution.reverseWords(s3) + "\"");
}
}
这种方法的优点:
- 原地操作,空间复杂度为 O(1),这是它的最大优势。
- 思路清晰,代码逻辑性强。
这种方法的缺点:
- 代码相对复杂,需要仔细处理各种边界情况。
- 时间复杂度略高,需要多次遍历字符串。
方法三:手动实现字符串分割和反转
除了使用编程语言提供的函数和双指针法,我们还可以手动实现字符串的分割和反转。这种方法可以帮助我们更深入地理解字符串处理的底层原理。
思路如下:
- 去除首尾空格: 首先,去除字符串首尾的空格。
- 分割字符串: 遍历字符串,手动分割单词。我们可以使用一个
StringBuilder
来存储单词,当遇到空格时,将StringBuilder
中的内容添加到一个列表中。 - 反转单词列表: 将单词列表反转。
- 拼接字符串: 将反转后的单词列表拼接成字符串,单词之间用一个空格分隔。
以 Java 为例,代码如下:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ReverseWords {
public String reverseWords(String s) {
// 1. 去除首尾空格
s = s.trim();
// 2. 分割字符串
List<String> wordList = new ArrayList<>();
StringBuilder word = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == ' ') {
if (word.length() > 0) {
wordList.add(word.toString());
word.setLength(0); // 清空 StringBuilder
}
} else {
word.append(s.charAt(i));
}
}
// 添加最后一个单词
if (word.length() > 0) {
wordList.add(word.toString());
}
// 3. 反转单词列表
Collections.reverse(wordList);
// 4. 拼接字符串
return String.join(" ", wordList);
}
public static void main(String[] args) {
ReverseWords solution = new ReverseWords();
String s1 = "the sky is blue";
String s2 = " hello world ";
String s3 = "a good example";
System.out.println("\"" + s1 + "\" 反转后: \"" + solution.reverseWords(s1) + "\"");
System.out.println("\"" + s2 + "\" 反转后: \"" + solution.reverseWords(s2) + "\"");
System.out.println("\"" + s3 + "\" 反转后: \"" + solution.reverseWords(s3) + "\"");
}
}
这种方法的优点:
- 可以更深入地理解字符串处理的底层原理。
- 代码逻辑清晰,易于理解。
这种方法的缺点:
- 代码相对复杂,需要手动处理各种细节。
- 效率可能不如使用编程语言提供的函数。
总结
总的来说,解决 LeetCode 151. 反转字符串中的单词 这道题,我们可以采用多种方法。选择哪种方法取决于具体的场景和需求。如果对空间复杂度没有特别高的要求,使用编程语言提供的字符串处理函数是最简单和高效的方法。如果对空间复杂度有严格要求,双指针法是更好的选择。手动实现字符串分割和反转可以帮助我们更深入地理解字符串处理的底层原理。
希望今天的讨论对大家有所帮助! 记住,刷 LeetCode 不仅仅是为了解决问题,更是为了提升我们的编程思维和解决问题的能力。Keep practicing, and you'll become a coding master!
SEO优化建议
为了让这篇文章更容易被搜索引擎收录,我们可以从以下几个方面进行优化:
- 关键词优化: 在文章标题和内容中合理地使用关键词,例如 "LeetCode", "反转字符串中的单词", "字符串处理", "双指针法" 等。
- 内容质量: 提供高质量、原创的内容,确保文章能够真正帮助读者解决问题。
- 结构化数据: 使用合适的标题、段落和列表,使文章结构清晰易读。
- 内部链接和外部链接: 在文章中添加内部链接,指向其他相关的文章;添加外部链接,指向权威的资源。
- 图片优化: 如果文章中包含图片,确保图片大小合适,并添加
alt
属性。
希望这些建议能够帮助你写出更具 SEO 友好的文章!