算法学习笔记 2023/04/12

今天学习的内容是字符串相关内容。

1. 反转字符串

这是一个字符串基本操作,有库函数实现的方法。不使用库函数的方法即双指针

344 反转字符串

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

顺便学习一下使用库函数的方法,c++中使用头文件#include<algorithm>即可使用reverse函数

#include<algorithm>
class Solution {
public:
    void reverseString(vector<char>& s) {
        reverse(s.begin(),s.end());
    }
};

2. 反转字符串2

字符串每遍历2k个字符反转前k个字符串,并且剩余不足2k的字符若大于k反转前k个字符串,小于k则全部反转。基本操作是相似的,但是增加了很多判断操作。

这道题关键的部分在于剪枝,去掉遍历中不是2k整数倍的元素,就可以大大的降低复杂度。如果不在这一步做剪枝处理,会导致后续的判例变得很复杂而且超时。

class Solution {
public:
    string reverseStr(string s, int k) {
        for(int i=0;i<s.size();i+=(2*k)){
            if(i+k>s.size()){
              for(int x=i,y=s.size()-1;x<y;x++,y--){
                  swap(s[x],s[y]);
              }
            }
            else {
                for(int x=i,y=i+k-1;x<y;x++,y--){
                    swap(s[x],s[y]);
              }
            }
        }
    return s;
    }
};

也可以自己定义一个类似库函数reverse的方法。

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 reverseStr(string s, int k) {
        for(int i=0;i<s.size();i+=(2*k)){
            if(i+k>s.size()){
                reverse(s,i,s.size()-1);
            }
            else {
                reverse(s,i,i+k-1);
                }
            }
    return s;
    }
};

题例 :541 反转字符串2

3. 替换空格

把字符串中每一个空格替换成“20%”。替换的20%是一个字符串,所以应该在空格下标insert()函数插入。但是这样复杂度不满足条件。

考虑到字符串的性质,创建一个新字符串result,遍历的过程中给result加上字符串是s[i],s[i]是 ' ' 空格的情况下,加上'%'+'2'+'0',返回result字符串即可。这种方法需要为新字符串开启存储空间。

class Solution {
public:
    string replaceSpace(string s) {
        string result;
        for(int i=0;i<s.size();i++){
            if(s[i]==' '){
                result=result+'%'+'2'+'0';
            }
            else result=result+s[i];
        }
        return result;
    }
};

使用双指针的方法,先计算需要给插入字符串让出的空间,再让两个指针同时从新旧字符串尾部位置向前遍历,不为空就赋值到新位置,遇到空值就向前赋值。这样的方式更加节省空间。

class Solution {
public:
    string replaceSpace(string s) {
        int count =0;
        for(int i=0;i<s.size();i++){
            if(s[i]==' '){
                count++;
            }
        }
        int old=s.size();
        s.resize(s.size()+count*2);   //加上原本的空格,每次插入需要2个额外的字符。
        int renew=s.size();
        for(int i=old-1, j=renew-1; j>i ;i--,j--){
            if(s[i]!=' '){
                s[j]=s[i];
            }
            else{
                s[j]='0';
                s[j-1]='2';
                s[j-2]='%';
                j-=2;
            }
        }
        return s;
    }
};

题例:替换空格

4. 翻转字符串的单词

这道题的难点在于单词长度不一致,用双指针直接翻转的话会导致很多错误。可以使用额外存储空间的话分割字符串再从尾到头生成新字符串。

不使用额外空间的方法,先把字符串全部翻转,再从头开始,把每一个单词翻转。需要注意!erase()函数本身复杂度为O(n),而不是O(1)。使用快慢指针除去多余的空格更方便。

这道题要分成三个部分来处理,首先是翻转字符串函数,按照前几题的写法即可

void reverse(string& s,int start,int end){
        for(int i=start,j=end;i<j;i++,j--){
            swap(s[i],s[j]);
       }
    }

第二部分是除去多出的空格,这一部分逻辑比较难理解,快指针顺序遍历,把快指针的值赋给慢指针位置,慢指针负责创建空格。

void exceptspace(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]!=' '){  //通过while循环把空格后的单词填充进去
                    s[slow++]=s[i++];
                }
            }
            s.resize(slow);
        }

翻转处理完的字符串逻辑就比较简单了。

string reverseWords(string s) {
        reverse(s,0,s.size()-1);
        exceptspace(s);
        int count=0;
        for(int i=0;i<=s.size();++i){
            if(s[i]==' '||i==s.size()){
                reverse(s,count,i-1);
                count=i+1;
            }
        }
        return s;
   }

题例:反转字符串中的单词

5. 左旋转字符串

把左侧前n个字符放到右侧。逻辑上不难,但是不额外使用空间的方法比较巧妙。先反转前n个字符串,再全部反转,再反转前s.size()-n个字符串。解题时要多注重数学逻辑的思考。

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]);
       }
    }
    void reverseLeft(string& s,int n){
        reverse(s,0,n-1);
        reverse(s,0,s.size()-1);
        reverse(s,0,s.size()-n-1);
    }
    string reverseLeftWords(string s, int n) {
        reverseLeft(s,n);
        return s;
    }
};

题例:左旋反转字符串

创建新字符串的方法,作练习:

class Solution {
public:
    string reverseLeftWords(string s, int n) {
        string result="";
        for (int i = n; i < s.size(); i++) result += s[i];
        for (int i = 0; i < n; i++) result += s[i];
        return result;
    }
};

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值