「这是我参与2022首次更文挑战的第16天,活动详情查看:2022首次更文挑战」。
大家好呀,今天我又是翻转蛋了。
今天解决翻转字符串中的单词,估计很多小婊贝一看到这个题,脑子里第一反应就是水题。
因为很多的编程语言都自带有库函数,几行代码就可以解决。
但是不行呀,这么玩儿这道难度中等的题,水题的帽子就带实了。
刷题初期还是要老老实实,少用现成的东西,自己老老实实的实现代码,编写对应的函数。
话至于此,接下来我们来开开心心肝题。
LeetCode 151 翻转字符串中的单词
题意
逐个翻转字符串 s 中的所有单词。
单词是由非空格字符组成的字符串,s 中使用至少一个空格将字符串中的单词分隔开。
返回一个翻转 s 中单词顺序并用单个空格相连的字符串。
示例
输入:s = "the sky is blue" 输出:"blue is sky the"
输入:s = " hello world "
输出:"world hello"
解释:输入字符串可以在前面或者后面包含多余的空格,但是翻转后的字符不能包括。
提示
- 1 <= s.length <= 10^4
- s 包括英文大小写字母、数字和空格 ' '。
- s 中至少存在一个单词。
题目解析
翻转字符串里的单词,难度可简单可中等。
这道题还是开头说的,用编程语言自带的库函数去解决,那就是一道几行代码的简单水题,这道题也就失去了意义。
为了配上这道题难度中等的身份,大家还是老老实实实自己动手实现对应函数。
毕竟,写代码是件快乐的事。
回到这道题本身上来,你想我们之前做过的反转字符串和反转字符串Ⅱ这俩,没看过的可以看下:
其实就是整体反转,再局部反转,反反得正,最后就解出来了。
不过说实话,这道题还是考察了挺多字符串的操作的,加上题目本身加的限制,整道题分 3 步解决:
- 去除多余空格。
- 反转整个字符串。
- 反转每个单词。
具体实现,接下来看图解。
图解
以 s = " hello world " 为例。根据题目解析中所说,图解分为 3 步。
# 初始化双指针
left, right = 0, len(s) - 1
第一步:去除多余空格。
去除多余空格总体来说是 3 个位置:开头、结尾、字符串内。
(1) 去除开头空格
左指针向右跑,碰到第一个不是空格的字符停下。
# 去除开头的空格
while left < right and s[left] == ' ':
left += 1
(2) 去除结尾空格
右指针像左跑,碰到第一个不是空格的字符停下。
# 去除结尾的空格
while left < right and s[right] == ' ':
right -= 1
(3) 去除字符串内多余空格
左指针向右跑,如果当前是字符,就往前跑,如果当前是空格,如果前一个不是空格,就往前跑,如果前一个也是空格,那这个空格就删掉,因为多余了。
# 去除单词间多余的空格
while left <= right:
if s[left] != ' ':
new_s.append(s[left])
# 如果当前是空格,且前一个字符不是空格,则添加
elif s[left] == ' ' and new_s[-1] != ' ':
new_s.append(s[left])
left += 1
第二步:反转整个字符串
反转字符串大家都很熟了,就是直接把字符串反转过来。
# 反转字符串
def reverseString(self, s):
# 初始化双指针
left, right = 0, len(s) - 1
# 这种方法可以不用判断元素奇偶
while left < right:
s[left], s[right] = s[right], s[left]
# 交换后,左指针右移,右指针左移
left += 1
right -= 1
return s
第三个:反转每个单词
首先初始化指向每个单词前后的指针。
# 初始化指向每个单词前后的指针
left, right = 0, 0
n = len(s)
之后右指针往右跑,跑完整个单词,然后单词反转。
whileleft < n:
while right < n and s[right] != ' ':
right += 1
s[left : right] = self.reverseString(s[left : right])
反转完一个单词,接着反转下一个单词。
本题的解决方式的时间复杂度显然为 O(n) 。
至于空间复杂度依照你所用的编程语言来确定,因为有的编程语言存在字符串不可修改的情况,比如 Python、Java,这就需要额外用一个数组来存储,那么它的空间复杂度就成了 O(n) 。
如果所用编程语言字符串支持修改,比如 C++,那空间复杂度为 O(1) 。
代码实现
Python 代码实现
class Solution:
# 去除多余空格
def removeSpaces(self, s):
# 初始化双指针
left, right = 0, len(s) - 1
# 去除开头的空格
while left < right and s[left] == ' ':
left += 1
# 去除结尾的空格
while left < right and s[right] == ' ':
right -= 1
# new_s 存储去掉多余空格剩下的东西
new_s = []
# 去除单词间多余的空格
while left <= right:
if s[left] != ' ':
new_s.append(s[left])
# 如果当前是空格,且前一个字符不是空格,则添加
elif s[left] == ' ' and new_s[-1] != ' ':
new_s.append(s[left])
left += 1
return new_s
# 反转字符串
def reverseString(self, s):
# 初始化双指针
left, right = 0, len(s) - 1
# 这种方法可以不用判断元素奇偶
while left < right:
s[left], s[right] = s[right], s[left]
# 交换后,左指针右移,右指针左移
left += 1
right -= 1
return s
# 反转每个单词
def reverseEachword(self, s):
# 初始化指向每个单词前后的指针
left, right = 0, 0
n = len(s)
while left < n:
while right < n and s[right] != ' ':
right += 1
s[left : right] = self.reverseString(s[left : right])
# 反转完一个单词,该反转下个单词了
left = right + 1
right += 1
return s
def reverseWords(self, s: str) -> str:
# 第 1 步:去除空格
s = self.removeSpaces(s)
# 第 2 步:反转字符串
s = self.reverseString(s)
# 第 3 步:反转每个单词
s = self.reverseEachword(s)
# 第 4 步:输出翻转后的字符串
return ''.join(s)
Java 代码实现
class Solution {
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;
}
/**
* 反转字符串指定区间[start, end]的字符
*/
public 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--;
}
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;
}
}
}
好啦,图解翻转字符串中的单词到这就结束辣。
搞清楚了题意然后一步步的写还蛮有意思的,整点 bug,搞搞自己。
这成就感不比直接调用几个库函数直接实现出来爽的多?
写代码真是这个世界上最有意思的事儿。
呃,剩下就是别忘了我的点赞呀,有什么问题留言区见,么么哒。
我是帅蛋,我们下次见!