代码随想录训练营Day8 | Leetcode 344、541、剑指Offer05、151、剑指Offer58-II
一、344 反转字符串
题目链接:344 反转字符串
核心:双指针,首尾交换,并依次向中间移动。
void reverseString(vector<char>& s) {
//双指针,首尾交换,然后同时向中间移动
int left=0;
int right=s.size()-1;
while(left<right)
{//left==right时指向同一个元素,无需交换,故退出循环
swap(s[left],s[right]);
left++;
right--;
}
}
二、541 反转字符串II
题目链接:541 反转字符串II
核心:指定范围的字符串反转的核心确定此范围,本题遍历时以2k为步长,每遍历2k个字符,判断剩余字符是少于k个还是大于等于k个,前者需全部反转,即范围是[i,end],后者仅反转前k个字符,即范围是[i,i+k-1]。
void reverse(string& s,int start,int end)
{//实现s的反转
while(start<end)
{
swap(s[start],s[end]);
start++;
end--;
}
}
string reverseStr(string s, int k) {
for(int i=0;i<s.size();i+=2*k)
{//遍历s,关键是“每计数至2k”的处理,其实用步长实现即可!
if(i+k<=s.size())
{//剩余字符>=k个(也存在剩余字符>=2k情况,不过也需要反转前k个,故归为一类)
reverse(s,i,i+k-1); //反转前k个字符,完成后进入下一个loop
continue;
}
//剩余字符小于k个,全部反转
reverse(s,i,s.size()-1);
}
return s;
}
三、剑指Offer 05 替换空格
题目链接:剑指Offer 05 替换空格
核心:要将空格填充为特殊字符,首先计算空格数,然后扩充原字符串大小为填充特殊字符后的大小,最后从后往前依次遍历字符串,遇到空格则填充,否则直接复制元素。
string replaceSpace(string s) {
//先扩充s大小,再从后往前遍历
int len=s.size();
int cnt=0;
for(char ch:s)
{//计算s中的空格数
if(ch==' ')
cnt++;
}
s.resize(s.size()+cnt*2);
int newlen=s.size();
int j=len-1; //j指向原字符串
for(int i=newlen-1;i>=0;i--)
{
if(s[j]!=' ')
{//不是空格直接复制即可
s[i]=s[j];
}
else
{//遇到空格则插入“%20”
s[i]='0';
s[i-1]='2';
s[i-2]='%';
i-=2; //需要向前移动2步,即此时i指向'%'
}
j--; //完成一次i的处理j需要向前移动1位
}
return s;
}
四、151 反转字符串中的单词
题目链接:151 反转字符串中的单词
核心:首先移除多余空格,然后反转整个字符串,最后反转单词,移除多余空格和反转字符串可作为2个子函数,被主函数调用实现,减少主函数的复杂度。
void reverse(string& s,int start,int end)
{//完成对字符串s从start开始到end结束之间所有元素的反转
while(start<end)
{
swap(s[start],s[end]);
start++;
end--;
}
}
void removeExtraspace(string& s)
{//双指针,fast遍历原s,slow指向有效元素得到新的s
int slow=0;
for(int fast=0;fast<s.size();++fast)
{
if(s[fast]!=' ')
{
if(slow>0)
s[slow++]=' '; //遇到下一个单词的开始,需要增加一个空格
while(fast<s.size() && s[fast]!=' ')
s[slow++]=s[fast++];
}
}
s.resize(slow); //循环结束时slow++,因此slow即新s的长度
}
string reverseWords(string s) {
//先去除多余空格,再将字符串整体反转,最后对单个单词反转,遇到空格则表示一个单词结束
removeExtraspace(s);//去除多余空格
int len=s.size();
reverse(s,0,len-1); //整体反转
int start=0;
for(int i=0;i<=len;++i)
{//遍历s,对单个单词反转
if(i==len || s[i]==' ')
{//找到一个单词,或者整个字符串就一个单词,即不存在空格
reverse(s,start,i-1); //注意i-1最终指向len-1的元素,故i<=len
start=i+1; //更新start,即下一个单词的开始
}
}
return s;
}
五、剑指Offer58-II 左旋转字符串
题目链接:剑指Offer58-II 左旋转字符串
核心:首先反转区间为前n的子字符串,然后反转区间为n至末尾的子字符串,最后反转整个字符串。
void reverse(string& s,int start,int end)
{
while(start<end)
{
swap(s[start],s[end]);
start++;
end--;
}
}
string reverseLeftWords(string s, int n) {
//先反转前n个元素,再反转后s.size()-n个元素,最后整体反转
reverse(s,0,n-1);
reverse(s,n,s.size()-1);
reverse(s,0,s.size()-1);
return s;
}