使用额外空间的方法
最先想到的方法是遍历字符串,将最终结果储存到结果字符串中。
因为每个单词的顺序都要翻转,所以从字符串的末尾开始向前遍历。由于是逆序遍历,为了保持每个单词不被改变,使用栈存储每个单词的字母,再输出后就可以恢复正常顺序。
对于冗余的空格,在遇到时只需将其出栈即可。
class Solution {
public:
string reverseWords(string s) {
stack<char> word_stack; // 储存每个单词
string result;
int i = s.length();
// 从字符串末端开始遍历
while (i-- > 0) {
// 将每个字符入栈
word_stack.push(s[i]);
// 如果遇到空格
if (s[i] == ' ') {
// 将空格出栈
word_stack.pop();
// 此时如果栈中有单词
if (!word_stack.empty()) {
// 将单词拼接到结果字符串中
while (!word_stack.empty()) {
result += word_stack.top();
word_stack.pop();
}
// 每个单词后加上空格
result += " ";
}
}
}
// 此时result是以空格结尾
// 若栈中没有单词了,则删掉空格
if (word_stack.empty()) {
result.erase(result.end() - 1);
}
// 否则拼接最后一个单词
else {
while (!word_stack.empty()) {
result += word_stack.top();
word_stack.pop();
}
}
return result;
}
};
字符串中的每个字符都执行了入栈和出栈两次操作,因此时间复杂度的 O ( n ) O(n) O(n),而由于额外使用了栈和结果字符串,空间复杂度也为 O ( n ) O(n) O(n)。
空间复杂度为O(1)的方法
但题目中说可以尝试空间复杂度为
O
(
1
)
O(1)
O(1)的方法。
不使用额外的辅助空间就需要原地翻转字符串。
对于一个字符串,要达到题目要求的翻转结果,可以翻转两次:
- 首先整体翻转,如:hello world → dlrow olleh
- 然后每个单词各自翻转,如:dlrow olleh → world hello
而对于冗余的空格,可以将字符串向左压缩。使用双指针,快指针遇到冗余空格则跳过,否则将其挪到慢指针的位置。最后慢指针之后的字符都是冗余的,使用resize()将其抛弃。
class Solution {
public:
// 翻转函数
void reverse(string& s, int left, int right) {
char temp;
while (left < right) {
temp = s[left];
s[left] = s[right];
s[right] = temp;
left++; right--;
}
}
string reverseWords(string s) {
// 利用双指针去除冗余空格
int slow = 0, fast = 0;
// 去除前面的空格
while (s[fast] == ' ')
fast++;
// 去掉单词间的冗余空格
s[slow++] = s[fast++]; //先赋第一个字符以省去边界判断
while (fast < s.length()) {
if (s[fast] != ' ' || (s[fast] == ' ' && s[fast - 1] != ' ') )
s[slow++] = s[fast];
fast++;
}
// 重置字符串大小
s.resize(slow);
if (s[s.length() - 1] == ' ')
s.pop_back();
// 第一次翻转
reverse(s, 0, s.length() - 1);
// 第二次翻转
slow = 0; fast = 0;
while (fast < s.length()) {
while (fast < s.length() && s[fast] != ' ')
fast++;
reverse(s, slow, fast - 1);
fast++;
slow = fast;
}
return s;
}
};