344.反转字符串。就头和尾相对移动交换就行。交换用swap()函数,也可以用中间量自己写。
一个函数实现反转就是:
void reverse(string& s,int f,int e)
{
if (f < 0 || e < 0 || f >= s.size() || e >= s.size()) {
return;
}
for(int i=f;i<=(e+f)/2;++i) //[f,**]注意是闭区间
{
swap(s[i],s[f+e-i]);
}
}
541.规律就是每隔2k个字符就反转前k个,所以一个循环就够了,主要是循环之内的那个交换左右反转子字符串的循环,j的边界条件要写对,还有交换元素的下标要写对。
class Solution {
public:
string reverseStr(string s, int k) {
for(int i=0;i<s.size();i+=2*k)
{
int len=k<(s.size()-i)?k:(s.size()-i);
for(int j=i;j<i+len/2;++j)
{
swap(s[j],s[2*i+len-j-1]);
}
}
cout<< s;
return s;
}
};
剑指Offer 05.替换空格。双指针法一个循环搞定。
class Solution {
public:
string reverseStr(string s) {
int count=0;
for(int i=0;i<s.size();++i)
{
if(s[i]==' ')count++;
}
int a=s.size()-1;
s.resize(s.size()+count*2);
int b=s.size()-1;
cout<<a<<" "<<b<<endl;
while(a<b)
{
if(s[a]==' ')
{
s[b--]='0';
s[b--]='2';
s[b--]='%';
a--;
}
else{
s[b--]=s[a--];
}
}
return s;
}
};
151、先整体反转,再每个单词反转就OK,但是自己写的总是显示越界错误:
class Solution {
public:
void reverse(string& s,int f,int e)
{
if (f < 0 || e < 0 || f >= s.size() || e >= s.size()) {
return;
}
for(int i=f;i<=(e+f)/2;++i) //[f,**]注意是闭区间
{
swap(s[i],s[f+e-i]);
}
}
string reverseWords(string s) {
int a=0,c=s.size()-1,b=0;
while (a < s.size() && s[a] == ' ') a++;
while (c >= 0 && s[c] == ' ') c--;
s.resize(c+1);
cout<<s<<endl;
int newIndex = 0;
for (int i = 0; i < s.size() - a; ++i) {
s[newIndex++] = s[i + a];
}
s.resize(newIndex);
s.resize(s.size()-a);
cout<<s<<endl;
reverse(s,0,s.size()-1);
c=s.size()-a;
while(b<=c)
{
while(s[b]!= ' ' && b<=c)
{
b++;
}
reverse(s,a,b-1);
cout<<s<<endl;
a=++b;
}
return s;
}
};
删除空格的时候变量用多了。其实还是快慢指针的思想,用一个index和一个i变量完成中间和两边所有多余空格的删除。注意在i不是空格的时候用把i指的那个元素赋给slow的那个元素,中间应该有的空格是判断slow不是第一个单词的话加上去,那么最后resize(slow)就行了,不会有错误。那个if语句里面也能统计单词个数。
class Solution {
public:
void reverse(string& s,int f,int e)
{
for(int i=f;i<=(e+f)/2;++i) //[f,**]注意是闭区间
{
swap(s[i],s[f+e-i]);
}
}
string reverseWords(string s) {
int a=0,c=s.size()-1,b=0;
while (a < s.size() && s[a] == ' ') a++;
while (c >= 0 && s[c] == ' ') c--;
cout<<"c is:"<<c<<endl;
int slow=0,count=0;
for(int i=0;i<s.size();++i)
{
if(s[i]!=' ')
{
count++;
if(slow!=0)s[slow++]=' ';
while(s[i]!=' '&&i<s.size())
{
s[slow++]=s[i++];
}
}
}
cout<<"处理后 "<<count<<" "<<s<<endl;
s.resize(slow);
reverse(s,0,s.size()-1);
a=0;
while(b<s.size())
{
while(s[b]!= ' ' && b<s.size())
{
b++;
}
reverse(s,a,b-1);
cout<<s<<endl;
a=++b;
}
return s;
}
};
58、左旋字符串:跟上面的题一样的思路,不过是先整体反转再局部反转。右旋也是一样,先整体反转再局部反转。
原下标(在下标前省略了a,0是指a0.):
0,1,2,3,4,……,n-1,n
整体反转:
n,n-1,…n-k+1,n-k…,4,3,2,1,0
局部反转。
n-k+1,……,n-1,n,0,1,2,3,4……n-k
这样就把后面k个一起挪到前面去了,把前面n-k+1个挪到后面去了。
总结:所以字符串的反转是很多问题的基本操作,一定注意。