算法训练day8|344. 反转字符串|541. 反转字符串 II|151. 反转字符串中的单词|剑指 Offer 58 - II. 左旋转字符串

本文介绍了多种字符串处理问题的C++解决方案,包括反转字符串、间隔反转字符串、替换空格、反转单词以及左旋转字符串。文章强调了双指针法和高效字符串操作的重要性,同时也提到了时间复杂度优化和内置函数的使用。
摘要由CSDN通过智能技术生成

一、344. 反转字符串

双指针互换即可

class Solution {
public:
    void reverseString(vector<char>& s) {
        int i,j;
        int size=s.size();
        for(i=0,j=size-1;i<size/2;i++,j--){
            swap(s[i],s[j]);
        }
        
    }
};

同时熟悉一下两个reverse函数

#include<cstring>
strrev(s)
#include<algorithm>
reverse(s.begin(),s.end());

二、541. 反转字符串 II

  1. 自己写的

为了处理逻辑:每隔2k个字符的前k的字符,写了一堆逻辑代码或者再搞一个计数器,来统计2k,再统计前k个字符。这算是常规思路,但是是麻烦了的。只要让i每次加2*k即可

class Solution {
public:
    string reverseStr(string s, int k) {
        int size = s.size();
        int count = size / (k*2);
        for(int j=0;j<count;j++){//前面 多个2*k的操作
            for(int L=0+j*2*k,R=k-1+j*2*k;L<(k*2)+j*2*k;L++){
                while(L<R){
                    swap(s[L++],s[R--]);
                }
            } 
        }
        //最后一个2*k单独操作
        if(size % (k*2) < k ){
            for(int L=0+count*2*k,R=size % (k*2)-1+count*2*k;L<size % (k*2)+count*2*k;L++){
                while(L<R){
                    swap(s[L++],s[R--]);
                }
            }
        }else{
            for(int L=0+count*2*k,R=k-1+count*2*k;L<(k*2)+count*2*k;L++){
                while(L<R){
                    swap(s[L++],s[R--]);
                }
            }
        }
        return s;
    
    }
};
  1. 看了题解后

时间复杂度其实没变,但是代码整洁了,只需要一次遍历,上面其实也是一次遍历,但是分成了几部分,会显得很复杂。

class Solution {
public:
    string reverseStr(string s, int k) {
        int size = s.size();
        for(int i=0;i<size;i+=2*k){
            if(i + k <= size){//前面还够2k个字符或剩余字符小于2k但大于等于k,即加上k还未到末尾
                reverse(s.begin()+i,s.begin()+i+k);
            }else{//最后面可能会不够完整的k,即加上k大于了size
                reverse(s.begin()+i,s.end());
            }
        }
        return s; 
    }
};

三、剑指 Offer 05. 替换空格

这题也是双指针,先增加s的长度,在从后往前遍历,遇到空格就变%20.

class Solution {
public:
    string replaceSpace(string s) {
        int count = 0;
        int size = s.size(); 
        for(int i=0;i<s.size();i++){
            if(s[i] == ' '){
                count++;
            }
        }   
        s.resize(s.size() + count * 2);
        for(int i=size-1,j=s.size()-1;i<j;){
            
            if(s[i] == ' '){
                s[j--] = '0';
                s[j--] = '2';
                s[j--] = '%';   
                i--;
            }else{
                s[j--] = s[i--];
            }
        }
        return s;
    }
};

四、151. 反转字符串中的单词

  1. for+erase去除空格

erase加上for循环,时间复杂度为O(n^2),删除的同时还会整体前移。

class Solution {
public:
    string reverseWords(string s) {
        //移除多余空格
        for(int i=1;i<s.size();i++){
            if(s[i] == ' ' && s[i] == s[i-1]){
                s.erase(s.begin()+i);
                i--;//需要注意到erase删除后,指针指向的数是发生了移动的,所以要回退一格
            }
        }
        //或者从后往前 删除时自动回退了
    //  for (int i = s.size() - 1; i > 0; i--) {
    //     if (s[i] == s[i - 1] && s[i] == ' ') {
    //         s.erase(s.begin() + i);
    //     }
    // }
        //处理前导空格
        while(s[0] == ' '){
            s.erase(s.begin());
        }
        //处理尾随空格
        while(s[s.size()-1] == ' '){
            s.erase(s.end()-1);
        }
        //整个反转
        reverse(s.begin(),s.end());
        //每个单词反转
        for(int i=0;i<s.size();){
            int j=i;
            while(s[j] != ' ' && j < s.size()){
            j++;
            }
            reverse(s.begin()+i,s.begin()+j);
            i = j+1;     
        }
        return s;

    }
};
  1. 双指针去除空格

因为不需要erase,而是遍历的过程中直接赋值,因此时间复杂度O(n),需要好好研究双指针。

class Solution {
public:
    string reverseWords(string s) {
        //移除多余空格
        int slow=0,fast=0;
        //前导空格
        while(s[fast] == ' ' && fast < s.size()){
            fast++;
        }
        while(fast < s.size()){
            if(s[fast] != ' '){
                s[slow++] = s[fast++];
            }else{
                //去除中间多余空格
                while(s[fast] == ' ' && fast < s.size()){
                    fast++;
                }
                //补上单词间空格
                s[slow++] = ' ';
            }
        }
        //去除末尾可能多出来的一个空格
        if(s[slow-1] == ' '){
            s.resize(slow-1);
        }else{
            s.resize(slow);
        }     
        //整个反转
        reverse(s.begin(),s.end());
        //每个单词反转
        int start = 0;
        for(int i=0;i<=s.size();i++){
            if(s[i] == ' ' || i == s.size()){
                reverse(s.begin()+start,s.begin()+i);
                start = i+1;
            }                      
        }
        return s;

    }
};

五、剑指 Offer 58 - II. 左旋转字符串

  1. 暴力解

用一个额外数组可以很简单ac

class Solution {
public:
    string reverseLeftWords(string s, int n) {
        //暴力的话需要用一个辅助数组
        string result;
        result.resize(s.size());
        int j = n;
        int i=0;
        while(j<s.size()){
            result[i++] = s[j++];
        }
        j=0;
        while(i<s.size()){
            result[i++] = s[j++];
        }
        return result;

    }
};
  1. reverse

左旋数组在数据结构里做过几次,三次reverse就能原地左旋,时间复杂度O(n)

class Solution {
public:
    string reverseLeftWords(string s, int n) {
        //先将两段分别反转,再整体反转,原地得到左旋
        reverse(s.begin(),s.begin()+n);
        reverse(s.begin()+n,s.end());
        reverse(s.begin(),s.end());
        return s;
    }
};
  1. substr

注意一下字符串的复制可以用substr(pos, len)。不加参数会复制整个字符串。

六、总结

对于字符串,有很多内置函数还是不太熟悉,复制、求长度、反转、复制子串等,多用多熟。

对于Cpp的string,a+=b的效率比a=a+b的效率要高,因为a+=b可以直接在a的末尾追加b,而不需要创建一个新的string对象来存储a和b的和。而a=a+b则需要创建一个临时的string对象来保存a和b的和,然后再赋值给a。这样就会增加内存分配和拷贝的开销。

(4小时)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值