题目描述
原题链接:151. 反转字符串中的单词
解题思路
- 先预处理头部空格和中间多余空格;
- 再将整体进行逆转。例如:
the sky is blue
—>eulb si yks eht
; - 最后,分别对每个单词进行逆转,即可完成反转字符串。例如:
eulb si yks eht
—>blue is sky the
。
一、采用erase处理
class Solution {
public:
// 预处理。注意:每次erase之后,都会改变s的长度,要更新指针位置
void preprocessingWords(string &s) {
// 删除头部空格
int i = 0;
while(s[i] == ' ') i++;
s.erase(0, i);
// 删除尾部空格
int j = s.size() - 1;
while(s[j] == ' ') j--;
s.erase(j + 1, s.size() - 1 - j); // 要用最新的长度
// 删除中间多余空格
int k = 0;
while(k < s.size() - 1) {
// 删除一个元素后,k位置保持不变,而此时k指向的字符为新字符,因此不需要再k++
if(s[k] == ' ' && s[k + 1] == ' ') {
s.erase(k, 1);
} else {
k++;
}
}
}
string reverseWords(string s) {
// 预处理
preprocessingWords(s);
// 整体逆转
reverse(s.begin(), s.end());
// 按单词逆转
int n = s.size();
int l = 0; // l:记录每个单词的首部位置
while(l < n) {
int r = l; // r:记录每个单词的末尾位置
while(r < n && s[r] != ' ') r++;
// 跳出循环时,为s[r] = ' ' 或 r = n,都为进行逆转条件
reverse(s.begin() + l, s.begin() + r); // 左闭右开,进行逆转
l = r + 1; // 更新下一轮逆值起点
}
return s;
}
};
时间复杂度
O
(
n
2
)
O(n^2)
O(n2) (erase为O(n),erase外还有一个while
O
(
n
2
)
O(n^2)
O(n2))
空间复杂度
O
(
1
)
O(1)
O(1)
二、采用移除元素解题方式预处理
采用 203. 移除链表元素 的方式去处理空格,使用快慢指针,快指针进行遍历,慢指针用来存储。
快指针遍历到非空格元素后,慢指针就依次存储。由于每个单词之间有一个空格并且开头和尾部没有空格,因此每次给非开头单词加一个空格,用来分割单词。
class Solution {
public:
void preprocessingWords(string &s) {
int n = s.size();
int i = 0; // 慢指针
for(int j = 0; j < n; j++) { // 快指针
if(s[j] != ' ') { // 当不为空格时,将单词加入到字符串中
if(i != 0) s[i++] = ' '; // 非开头单词时,每次为填充单词前,加一个空格
while(j < n && s[j] != ' ') s[i++] = s[j++]; // 填充单词
}
}
s.resize(i);
}
string reverseWords(string s) {
// 预处理
preprocessingWords(s);
// 整体反转字符串
reverse(s.begin(), s.end());
// 反转每个单词
int n = s.size();
int l = 0; // l:记录每个单词的首部位置
while(l < n) {
int r = l; // r:记录每个单词的末尾位置
while(r < n && s[r] != ' ') r++;
// 跳出循环时,为s[r] = ' ' 或 r = n,都为进行逆转条件
reverse(s.begin() + l, s.begin() + r); // 左闭右开,进行逆转
l = r + 1; // 更新下一轮逆值起点
}
return s;
}
};
时间复杂度
O
(
n
)
O(n)
O(n)
空间复杂度
O
(
1
)
O(1)
O(1)
参考文章:151.翻转字符串里的单词