一、题目信息
力扣链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
代码随想录:代码随想录
参考:代码随想录(卡哥yyds!!!!!!!!!!)
二、思路:
1. 先整体的来把字符串进行翻转:
abc defg -> gfed cba
2. 然后利用空格作为关键信息来对单个单词重新翻转一下:
gfed cba -> defg abc
三、主要困难:
空格出现的位置很刁钻,而且个数也很难搞,比如说字符串
" Hello World "
按照题目要求,字符应该以字母开始以字母结束,所以两端的这些空格都要灭掉;单词之间还只能保留一个空格,所以中间的空格也需要进行处理。
四、代码:
class Solution {
public:
void reverse(string& s, int start, int end) // 定义交换元素的函数
{
for (int i = start, j = end; i < j; i++, j--)
{
swap(s[i], s[j]);
}
}
string reverseWords(string s) {
int slow_index = 0;
int fast_index = 0;
// 先想办法去掉字符串开头的空格 用快指针遍历到第一个非空的位置
while(s[fast_index] == ' ')
{
fast_index ++;
}
// s[slow_index++] = s[fast_index]; // 找到了第一个不是空格的元素,就把这个值赋给慢指针 这个地方不对哦慢指针不用动
for(; fast_index < s.size();fast_index++)
{
if(fast_index-1>0 && s[fast_index] == ' ' && s[fast_index-1] == ' ') // 这个地方的fast_index-1不能说来就来的,必须得考虑这个地方有没有超出范围,然后如果碰到了一个位于中间部位的空格还必须得保留一个,fast_index 第一次进入空格位置的时候slow_idex是直接把值读过去的,所以就有了一个空格,之后的fast就是要遍历找到下一个非空格的位置
{
continue; // 这个continue,直接跳过了之后的所有语句,也是很绝!
}
else
{
s[slow_index++] = s[fast_index];
// 这里注意,交换的是元素,不是元素和序号进行交换,我说为啥我换完之后一堆空格哈哈哈哈哈哈
}
}
// 去掉末尾的空格 如果原始字符串的最后位置是一连串空格,那么我的slow_index 就不可避免读取到了一个空格,所所以我得看看循环终止之后我的slow_index指向的到底是什么
// 这里需要注意的是,如果原始字符串末尾还有好多空格的话,当上边的操作结束之后,s更新了最后一位,是个空格,而且slow_index也+1了。
// 因此在看字符串最后一位的时候,看的是slow-1,既然-1了,自然还要看是不是超范围
if (slow_index - 1 > 0 && s[slow_index - 1] == ' ')
{
s.resize(slow_index-1);
}
else
{
s.resize(slow_index); // 重新设置字符串大小
}
reverse(s,0,s.size()-1);
int start = 0; //removeExtraSpaces后保证第一个单词的开始下标一定是0。
for (int i = 0; i <= s.size(); i++) {
if (i == s.size() || s[i] == ' ') { //到达空格或者串尾,说明一个单词结束。进行翻转。
reverse(s, start, i - 1); //翻转,注意是左闭右闭 []的翻转。
start = i + 1; //更新下一个单词的开始下标start
}
}
return s;
}
};
五、代码说明:
1. 第一个环节定义了一个用来翻转字符串的函数,传入待翻转字符串,起始位置,终止位置,利用swap(a,b)实现字符串翻转;
2. 第二个环节实现对字符串的初加工,去除首位空格,以及单词之间的空格,采用双指针法。
2.1 起始空格处理:快慢指针均指向0位置,快指针向后遍历至遇到第一个不为空格的字符,赋值给慢指针指向的字符串位置
2.2 中间空格处理:利用判断条件 if(fast_index-1>0 && s[fast_index] == ' ' && s[fast_index-1] == ' '),如果快指针遍历过程中发现刚刚遍历的位置(fast-1)是个空格,fast位置还是空格,那就continue跳过去,继续往前走,否则就要给慢指针指向的位置赋值了;
2.3 末尾空格处理:当fast指针遍历结束之后,slow更新s的过程也就停止了,需要注意的是,在我的这个程序里边尽管s不再更新了,但是slow还是自加1了,这个地方导致我错了好多次……蠢哭了。而且如果原始字符串末尾有空格,那么更新之后的字符串末尾也保留了一个空格,需要后边进行处理
3. 第三个环节要对字符串长度进行更新,在处理之前,需要看字符串末位是不是空格,此时的字符串末尾对应的是slow-1!!!,如果是空格,那resize的时候就是slow-1,否则就是slow,这个size返回的是整个s的长度,所以slow作为序号是比这个size大1的
4. 第四个环节,以空格为标志,定义快慢指针对单词在进行一遍翻转。
end!