programmercarl.com/0151.%E7%BF...
给你一个字符串 s ,请你反转字符串中 单词 的顺序。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。
注意: 输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
示例 1:
ini
输入: s = "the sky is blue"
输出: "blue is sky the"
示例 2:
ini
输入: s = " hello world "
输出: "world hello"
解释: 反转后的字符串中不能存在前导空格和尾随空格。
示例 3:
ini
输入: s = "a good example"
输出: "example good a"
解释: 如果两个单词间有多余的空格,反转后的字符串需要将单词间的空格减少到仅有一个。
提示:
1 <= s.length <= 104s包含英文大小写字母、数字和空格' 's中 至少存在一个 单词
进阶: 如果字符串在你使用的编程语言中是一种可变数据类型,请尝试使用 O(1) 额外空间复杂度的 原地 解法。
这道题目可以说是综合考察了字符串的多种操作。
一些同学会使用split库函数,分隔单词,然后定义一个新的string字符串,最后再把单词倒序相加,那么这道题题目就是一道水题了,失去了它的意义。
所以这里我还是提高一下本题的难度:不要使用辅助空间,空间复杂度要求为O(1)。
不能使用辅助空间之后,那么只能在原字符串上下功夫了。
想一下,我们将整个字符串都反转过来,那么单词的顺序指定是倒序了,只不过单词本身也倒序了,那么再把单词反转一下,单词不就正过来了。
所以解题思路如下:
- 移除多余空格
- 将整个字符串反转
- 将每个单词反转
举个例子,源字符串为:"the sky is blue "
- 移除多余空格 : "the sky is blue"
- 字符串反转:"eulb si yks eht"
- 单词反转:"blue is sky the"
这样我们就完成了翻转字符串里的单词。
使用双指针法来去移除空格,最后resize(重新设置)一下字符串的大小,就可以做到O(n)的时间复杂度。
java
void removeExtraSpaces(string& s) {//去除所有空格并在相邻单词之间添加空格, 快慢指针。
int slow = 0; //整体思想参考https://programmercarl.com/0027.移除元素.html
for (int i = 0; i < s.size(); ++i) { //
if (s[i] != ' ') { //遇到非空格就处理,即删除所有空格。
if (slow != 0) s[slow++] = ' '; //手动控制空格,给单词之间添加空格。slow != 0说明不是第一个单词,需要在单词前添加空格。
while (i < s.size() && s[i] != ' ') { //补上该单词,遇到空格说明单词结束。
s[slow++] = s[i++];
}
}
}
s.resize(slow); //slow的大小即为去除多余空格后的大小。
}
kotlin
class Solution {
/**
* 1.去除首尾以及中间多余空格
* 2.反转整个字符串
* 3.反转各个单词
*/
fun reverseWords(s: String): String {
// 1.去除首尾以及中间多余空格
val sb: StringBuilder = removeSpace(s)
// 2.反转整个字符串
reverseString(sb, 0, sb.length - 1)
// 3.反转各个单词
reverseEachWord(sb)
return sb.toString()
}
private fun removeSpace(s: String): StringBuilder {
var start = 0
var end = s.length - 1
while (s[start] == ' ') start++
while (s[end] == ' ') end--
val sb = StringBuilder()
while (start <= end) {
val c = s[start]
if (c != ' ' || sb.get(sb.length - 1) != ' ') {
sb.append(c)
}
start++
}
return sb
}
/**
* 反转字符串指定区间[start, end]的字符
*/
fun reverseString(sb: StringBuilder, start: Int, end: Int) {
var start = start
var end = end
while (start < end) {
val temp = sb.get(start)
sb.setCharAt(start, sb[end])
sb.setCharAt(end, temp)
start++
end--
}
}
private fun reverseEachWord(sb: StringBuilder) {
var start = 0
var end = 1
val n = sb.length
while (start < n) {
while (end < n && sb[end] != ' ') {
end++
}
reverseString(sb, start, end - 1)
start = end + 1
end = start + 1
}
}
}
- 时间复杂度: O(n)
- 空间复杂度: O(1) 或 O(n),取决于语言中字符串是否可变