一、反转字符串中单词
本题上来我想到了用空格检索作为分界点,然后进行反转,但是想不到如何让单词整体反转的同时,还要保留空格。这道题涉及的知识点真的非常多,也非常有意思。
第一,需要去掉多余的空格(包括开头的空格、后尾的空格、以及中间多余的空格)。去掉空格又用了三种不同的方法:
1.开头的空格先让快指针平移,直到检索到第一个不为空格的值,然后开始进行字符串的覆盖
2.去除中间空余部分的空格包含在了用快慢指针覆盖这一过程中,具体操作是检测到快指针当前指向空格,并且它的前方也是空格,利用continue跳出本次循环,什么操作都不做。
3.尾部空格的去除运用了缩小字符串长度直接对多余空间进行删除。具体操作是,用慢指针检索尾部是否有空格(这里的空格一定只有一个,不会存在多个,因为第二步覆盖操作时已经利用continue去掉了连续的空格),如果有空格,就把字符串利用resize重新定义长度。这里有一个细节是,low指针在前面覆盖操作的时候,最后有一步low++的自增了,所以在下表中,指向的是末尾元素的后一位,因此检查最后一位是不是空格的指针是low-1指针而不是low指针。最后用resize缩小长度时,如果有空格就变成low-1,如果不是空格长度就是low。具体可以参考下图:
第二、在把所有的字符串换成统一格式以后,现在字符串的结构都是“abcd dc ed df”了,现在需要做的操作是先将整个字符串反转,变成“fd de cd dcba”。然后再以空格和a后面的末尾指针(s.size())为分界,进行局部反转,变成“df ed dc abcd”。反转时,需要用自己编写的reverse()函数,这里有一个注意点是:reverse函数传参string&s,int start,int end。s前面要加&符号,因为要对原字符串进行操作,因此需要带回原值。
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 low=0;
int fast=0;
//去前导空格
while(fast<s.size()&&s[fast]==' '){
fast++;
}
//去中间空格
for(;fast<s.size();fast++){
if(s[fast]==' ' && s[fast-1]==' '){
continue;
}
else{
s[low++]=s[fast];
}
}
//去末尾空格
if(low<s.size()&&s[low-1]==' '){//low在上一步赋值的时候有自增,也就是说,low目前指向的是空格之后一位
s.resize(low-1);
}
else{
s.resize(low);
}
//字符串倒序
reverse(s,0,s.size()-1);
for(int i=0,j=0;i<=s.size();i++){
if(i==s.size()||s[i]==' '){
reverse(s,j,i-1);
j=i+1;
}
}
return s;
}
};
二、右旋转字符串
类似反转单词,前者是用空格做分界,后者是用长度做分界,这里还运用了algorithm库函数中的reverse,利用迭代器直接进行反转,比用手写的用长度反转更便捷
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
int k;
string s;
cin>>k;
cin>>s;
reverse(s.begin(),s.end());
reverse(s.begin(),s.begin()+k);
reverse(s.begin()+k,s.end());
cout<<s<<endl;
}