Hello大家好,这是一道在字符串题目中有关双指针解法的题目,属于比较经典又有操作性和复杂度的例题,因而拿出来做讲解,详细介绍送给大家💝
原题传送门
给你一个字符串 s ,请你反转字符串中 单词 的顺序。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。
注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
示例 1:
输入:s = “the sky is blue”
输出:“blue is sky the”
示例 2:
输入:s = " hello world "
输出:“world hello”
解释:反转后的字符串中不能存在前导空格和尾随空格。
示例 3:
输入:s = “a good example”
输出:“example good a”
解释:如果两个单词间有多余的空格,反转后的字符串需要将单词间的空格减少到仅有一个。
代码很简洁,知道思路有了,双指针的代码并不难写,C/C++代码如下🌾
class Solution {
public:
void reverseString(vector<char>& s) {
int left = 0;
int right = s.size() - 1;
while(left < s.size()/2)
swap(s[left++],s[right--]);
}
};
想知道如何实现这几步吗,那就听我娓娓道来🔍
void removeExtraspaces(string& s)
{
//移除字符串当中的多余空格
for(int i = s.size() - 1;i > 0; --i)
{
if(s[i] == s[i - 1] && s[i] == ' ')
s.erase(s.begin() + i);
}
//移除前导空格
if(s.size() > 0 && s[0] == ' ')
s.erase(s.begin());
//移除尾随空格
if(s.size() > 0 && s[s.size() - 1] == ' ')
s.erase(s.begin() + s.size() - 1);
}
先行给出C++代码
void removeExtraSpaces(string& s)
{
int slow = 0;
for(int fast = 0;fast < s.size(); ++fast)
{
if(s[fast] != ' ') //当快指针指向不为空格时,进行互相替换
{
if(slow != 0) //解决每个单词之间的空格
s[slow++] = ' ';
//若slow当前为0,则直接替换,为了解决前导空格
while(fast < s.size() && s[fast] != ' ')
s[slow++] = s[fast++]; //指针元素互换,直到一个单词结束
}
}
s.resize(slow); //慢指针当前所指位置即为去空格后数组大小
}
交替过程展示
还是一样,一张张分部图解手撕算法,为的是能让大家看清指针走的每一步,所以不要怕麻烦,跟着我一步一步来🚶
①首先,只有当fast快指针指向不为空时才做,交替,但一开始快指针指向首除,因此不进if(s[fast] != ’ ')的判断,fast快指针直接后移
②若快指针遍历到不为空,与慢指针进行替换,此处进入的是这个while循环,而不是if(slow != 0)这个判断,因为此时慢指针是指向位置0的,所以直接进行交替即可,也就是这样的操作,可以代替erase()的那一小部分的前置空格的操作
while(fast < s.size() && s[fast] != ' ')
s[slow++] = s[fast++]; //指针元素互换,直到一个单词结束
③接下来注意了,这是一个while循环,此时并没有跳出这个while循环,因为快指针还没有遍历到空格而且快指针还没到达末尾,所以在上一次替换之后,双指针后移,继续进行一个替换操作,这时候第二个字母e就被继续替换
- 这个单词while循环后面是一样的操作,不做赘述,进入关键一步🔑
④在交替放置完字母o之后,双指针同时后移,这时候快指针碰到了空格,即跳出while循环
⑤这个时候回到最初的大循环,fast指针后移一位,发现后面还是空格,所以再移动一位,这个时候边碰到了字母w,进入if(s[fast] != ’ ') 这个if分支的判断
for(int fast = 0;fast < s.size(); ++fast)
if(slow != 0) //解决每个单词之间的空格
s[slow++] = ' ';
⑥接着就是下一个单词的交替赋位,从下图可以看出,#hello#和#world#之间是有一个空格的,很好的解决了前面的所有空格
⑦最后一步,就是解决最后面的后置空格了,此时在字母’d’赋位完后,双指针同时向后移动,快指针fast便指向了空,所以不进入任何分支判断,fast指针继续后移,超出字符串边界,自动结束外层for循环的遍历,此时进行这一步操作,使用resize()函数重新开始数组空间,慢指针slow当前所指位置即为新数组大小
s.resize(slow); //慢指针当前所指位置即为去空格后数组大小
这就是去除所有空格后的结果,大家在做完一个功能之后就可以点击#执行代码#看看是否成功
好,接下来我们进入第二步,也就是在去除了多余空格后,我们需要将整个字符串进行一个反转,其实这个就是开头讲到的那道题
void reverseString(string& s,int start,int end)
{
for(int i = start,j = end;i < j;++i,--j)
swap(s[i],s[j]);
}
这是反转后的样子,可以看出,就差把单个单词进行逐一翻转了
好的,最后就来到了我们反转单个单词的部分,加油,快爬到山顶了⛰
//3.反转单个单词
int start = 0; //标记每个单词的起始位置
for(int i = 0;i <= s.size(); ++i)
{
//直到遍历到一个空格位置才算结束一个单词
if(i == s.size() || s[i] == ' ')
{ //i == s.size() - 遍历到最后一个单词的末尾要单独判断,因为其后无空格
reverseString(s,start,i - 1); //反转单词
start = i + 1; //更新下一个单词的起始位置
}
}
reverseString(s,start,i - 1);
class Solution {
public:
void removeExtraSpaces(string& s)
{
int slow = 0;
for(int fast = 0;fast < s.size(); ++fast)
{
if(s[fast] != ' ') //当快指针指向不为空格时,进行互相替换
{
if(slow != 0) //解决每个单词之间的空格
s[slow++] = ' ';
//若slow当前为0,则直接替换,为了解决前导空格
while(fast < s.size() && s[fast] != ' ')
s[slow++] = s[fast++]; //指针元素互换,直到一个单词结束
}
}
s.resize(slow); //慢指针当前所指位置即为去空格后数组大小
}
void reverseString(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) {
//1.移除给出字符串中的多余空格
removeExtraSpaces(s);
//2.反转整个字符串
reverseString(s, 0, s.size() - 1);
//3.反转单个单词
int start = 0; //标记每个单词的起始位置
for(int i = 0;i <= s.size(); ++i)
{
//直到遍历到一个空格位置才算结束一个单词
if(i == s.size() || s[i] == ' ')
{ //i == s.size() - 遍历到最后一个单词的末尾要单独判断,因为其后无空格
reverseString(s,start,i - 1); //反转单词
start = i + 1; //更新下一个单词的起始位置
}
}
return s;
}
};
本题的讲解到这里就结束了,怎么样,这波字符串与双指针的搭配有没有震撼到你,原来双指针还可以这么去操纵字符串,如果您对讲解的哪处有所疑问,可以于评论区或者私信我,感谢您对本文的观看🌹
以下是在剑指Offer里相关的题型,在看完本题可以去继续去练练手