1.秒了,有什么好说的?(开玩笑的,不过确实很简单,唯一需要注意的就是中间点的选取,选个简单例子模拟一下也清楚了)
2.字符串翻转方式大抵有两种(不包含库函数reverse),一是用临时变量temp完成数据交换,二是采用异或操作符(^)位运算完成(有兴趣的同学可自行了解)
class Solution {
public:
void reverseString(vector<char>& s) {
for(int i=0;i<s.size()/2;i++){
char temp=s[i];
s[i]=s[s.size()-i-1];
s[s.size()-i-1]=temp;
}
}
};
1.感觉不难但自己没有做出来,习惯写i++,但i+=2k的写法把问题分成若干段,极大地统一了处理逻辑,这种思想很重要。
2.剩余元素>=k个和>=2k个处理逻辑是一样的都是逆转前k个,所以只需要一个if一个else。(此外调用库函数reverse注意参数是容器或数组初始位置和结束位置的迭代器位置)
class Solution {
public:
string reverseStr(string s, int k) {
int len=s.size();
for(int i=0;i<len;i+=(2*k)){//每一次循环i+2k
if(i+k>len)//等价于i+k>len,即剩余元素不足k个
reverse(s.begin()+i,s.end());
else//等价于i+k<=len||i+2*k<=len即剩余元素>=k个或>=2k个
reverse(s.begin()+i,s.begin()+i+k);
}
return s;
}
};
1.没有考虑要增加空间,以为只是简单的替换,我是憨包……(注意if('0'<=s[i]&&s[i]<='9')这种写法,意味着我们并不需要知道数字的ASCⅡ值)
2.为什么要从后往前插入?(因为从前往后每次插入都要整体后移,时间复杂度是O(n2),所以一般选择先扩容空间再从后往前填入元素这样复杂度是O(n))
3.为什么循环条件设成i<j?(因为当i=j的时候正好填充完第一个数字带来的填充需求,之后字符串不用改变了)
#include<iostream>
using namespace std;
int main(){
string s;
while(cin >> s){
int count =0;
int oldsize=s.size();
for(int i=0;i<s.size();i++){//统计有几个数字
if('0'<=s[i]&&s[i]<='9')
count++;
}
s.resize(s.size()+count*5);//根据数字多少增加空间
int newsize=s.size();
for(int i=newsize-1,j=oldsize-1;j<i;i--,j--){
if(s[j]<'0'||s[j]>'9')
s[i]=s[j];//不是数字就直接替换
else{//是数字就插入单词
s[i]='r';
s[i-1]='e';
s[i-2]='b';
s[i-3]='m';
s[i-4]='u';
s[i-5]='n';
i-=5;
}
}
cout << s << endl;
}
}
1.最乱的一集(其实核心是去除空格函数,翻转处理好的字符串再翻转每个单词的逻辑其实很好理解)
2.去除空格函数逻辑:去又没完全去,因为每两个单词之间是要保留一个空格的。所以第一个单词是特殊的,它前面没有单词不需要加空格,需要特殊处理。其次我们采用的是快慢指针法,把快指针i指向的每一个字母都赋值给慢指针。所以我们的处理逻辑是这样的:快指针遍历字符串,第一个单词之前不用加空格,单独处理,之后每遇到一个单词先加一个空格再把单词里面的字母赋值给慢指针,所以里面的while是处理每个单词的循环,整体的时间复杂度还是O(n)。
3.使用库函数reverse要注意迭代器位置的选取,以及翻转每个单词的逻辑及边界情况处理。
class Solution {
public:
void removeExtraSpace(string &s){//去除空格函数
int slow=0;
for(int i=0;i<s.size();i++){
if(s[i]!=' '){//不等于空格时才操作,相当于有空格就删除
if(slow!=0) s[slow++]=' ';//如果不是首个单词每遍历一个新单词都要在前面加个空格
while(i<s.size()&&s[i]!=' ')//一口气把这一个单词处理完
s[slow++]=s[i++];
}
}
s.resize(slow);//处理好的字符串
}
string reverseWords(string s) {
removeExtraSpace(s);//去空格
reverse(s.begin(),s.end());//翻转整个字符串
int start=0;
for(int i=0;i<=s.size();i++){//翻转每个单词
if(i==s.size()||s[i]==' '){
reverse(s.begin()+start,s.begin()+i);
start=i+1;
}
}
return s;
}
};
1.应该在408数据结构真题中出现过,且有了上一题的铺垫,这一题就不难了。(先局部逆置再整体逆置与先整体逆置再局部逆置的效果是一样的)
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
int k;
string s;
cin >> k >> s;
reverse(s.begin(),s.begin()+s.size()-k);//先局部逆置
reverse(s.begin()+s.size()-k,s.end());
reverse(s.begin(),s.end());//再整体逆置
cout << s << endl;
}
今日总结:easy与middle齐飞。