代码随想录之字符串

**

344. 反转字符串

v思路描述:
之前其实说过,一般情况下对于数据的线性操作我们都可以采用多指针法来做(一般双指针即可),本题一样,我们使用一个left指向最左边,一个right指向最右边,然后我们从两边往中间进行遍历,每遍历一个就进行一次交换即可。
**
在这里插入图片描述

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

**

541. 反转字符串 ||

**
题目描述:在这里插入图片描述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 resversijf(string s,int k){ for(int i=0;i<s.size();i+=(2*k)){ if(i+k<=s.size()){ reverse(s.begin()+i,s.begin()+i+k); continue; } reverse(s.begin()+i,s.begin()+s.size()); } return s; } }
**

05. 替换空格

**
在这里插入图片描述

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

151. 翻转字符串里的单词

在这里插入图片描述
1.去除首尾以及中间多余空格
2.反转整个字符串
3.反转各个单词

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 removeExtraspaces(string&s){
        int slowIndex = 0,fastIndex=0;
        //去除开头的冗余空格
        while(s.size()>0 && fastIndex<s.size() && s[fastIndex]==' '){
            fastIndex++;
        }
        //去除字符串中间部分的冗余空格
        for(;fastIndex<s.size();fastIndex++){
            if(fastIndex-1>0 && s[fastIndex-1]==s[fastIndex] && s[fastIndex]==' '){
                continue;
            }
            else{
                s[slowIndex++]=s[fastIndex];
            }
        }
        //去除字符串末尾空格
        if(slowIndex-1>0 && s[slowIndex-1]==' '){
            s.resize(slowIndex-1);
        }
        else{
            s.ressize(slowIndex);
        }
    }
    string reversewords(string s){
        removeExtraspaces(s);
        reverse(s.begin(),s.end()-1);
        int start = 0;
        int end=0;
        bool entry = false;
        for(int i=0;i<s.size();i++){
            //翻转的入口下标
            if(!entry){
                start=i;
                entry = true;
            }
            //翻转的结束下标
            if(entry&&s[i]==' '&&s[i-1]!=' '){
                end=i-1;
                entry = false;
                reverse(s,start,end;)
            }
            //最后一个单词没有空格的情况
            if(entry && (i==(s.size()-1)) && s[i]!=' '){
                end=i;
                entry = false;
                reverse(s,start,end);
            }
        }

    }
    return s;
}

**

58. ||. 左旋转字符串

**
在这里插入图片描述

class Solution{
    public:
    string reverseleftwords(string s, int n){
        //翻转前n个字符
        reverse(s.begin(),s.begin()+n);
        //翻转n到末尾的字符
        reverse(s.begin()+n,s.end());
        //翻转整个字符串
        reverse(s.begin(),s.end());
        return s;
    }
}

**

28. 实现strStr()(使用KMP算法)

**
在这里插入图片描述
思路:
KMP算法的典型应用,顺便好好的把KMP算法给理解一波。

假如现在有两个字符串,一个是文本串aabaabaaf,另一个是模式串aabaaf。
我们现在要做的是找到该模式串第一次在文本串中出现的位置或者该模式串是否被包含在该文本串中。
使用KMP算法的第一步就是要先得到一个前缀表,即我们熟知的next数组。
这个表怎么得到?
得到前缀表之前我们首先要明确什么是前缀什么又是后缀:

前缀是包含首字母且不包含尾字母的所有子串都称为前缀串,简称前缀。
以上面的模式串aabaaf为例,它的前缀串为a、aa、aab、aaba、aabaa;但是aabaaf则不是前缀串。
同理,后缀即只包含尾字母不包含首字母的所有子串。
还是以aabaaf为例,它的后缀串为:f、af、aaf、baaf、abaaf;
但是aabaaf则不是前缀串。

现在我们要找的就是最长相等前后缀(就是普遍认知上的最长公共前后缀,一个意思),我们对模式串进行逐个分析:

对子串a来说,既无前缀也无后缀(参考前后缀定义),所以为最长相等前后缀长度为0;
对aa,前缀为a,后缀为a,所以最长相等前后缀为1;
同理对于aab,最长前缀为aa,最长后缀为ab,但不相等,所以最长相等前后缀为0;
依次类推,对于aaba,最长相等前后缀为1;
对于aabaa,最长相等前后缀为2;
对于aabaaf,最长相等前后缀为0;

综上,我们就能够得到一个序列,0、1、0、1、2、0;
这个序列实际上就是我们针对于模式串aabaaf的前缀表:在这里插入图片描述

现在我们使用这个表来进行KMP匹配:在这里插入图片描述

从上图可以看到当匹配到b与f时,是出现矛盾即不匹配的时候,那么现在我们就要得到模式串的最大相等前后缀的长度,然后让回溯指针跳到与其相等的前缀的后面:

以上面为例,我们可以知道该模式串aabaaf的最长相等前后缀长度为2(前缀表中是有记录的,查看发生冲突位置处的前一个位置即最大相等前后缀,这里为2),那么我们现在就让指针跳到前缀后面一位即可,以指前缀表数组下标对应关系如下:在这里插入图片描述

那么让指针到前缀后面的位置即下标为2的位置即可,从此处又开始遍历查找。

循环上述查找过程即可。
有些kmp算法的具体实现中会有将next数组整体右移(-1、0、1、0、1、2)或者整体-1(-1、0、-1、0、1、-1)的操作,都是为了方便匹配不需要去找下一个罢了,但思想都是一样的,具体问题具体分析:

整体右移之后不难发现,右移之后那么发生冲突位置处的next数组元素值就是所求的最长相等前后缀的值。
整体-1这个感觉和原始的方式没什么区别…因为-1之后再次查找指针回溯位置还是要+1的,所以就不管了。

如何得到next数组呢?
伪代码总共四步为:
1、初始化数组
2、找出前后缀不相同情况
3、找出前后缀相同情况
4、更新next前缀数组的元素值

class Solution{
    public:
    void getNext(int*next,const string&s){
        int j=-1;
        next[0]=j;
        for(int i=1; i<s.size();i++){
            while(j>=0 && s[i]!=s[j+1]){
                j=next[j];
            }
            if(s[i]==s[j+1]){
                j++;
            }
            next[i]=j;
        }
    }
    int strStr(string haystack, string needle){
        if(needle.size()==0){
            return 0;
        }
        int next[needle.size()];
        getNext(next,neddle);
        int j=-1;
        for(int i=0;i<haystack.size();i++){
            while(j>=0 && haystack[i]!=needle[j+1]){
                j=next[j];
            }
            if(haystack[i]==needle[j+1]){
                j++;
            }
            if(j==(needle.size()-1)){
                return (i-needle,size()+1)
            }
        }
        return -1;
    }
}

**

459. 重复的子字符串

**
在这里插入图片描述

class Solution{
    public:
    void getNext(int *next,const string&s){
        next[0]=-1;
        int j=-1;
        for(int i=1;i<s.size();i++){
            while(j>=0 && s[i]!=s[j+1]){
                j=next[j];
            }
            if(s[i]==s[j+1]){
                j++;
            }
            next[i]=j;
        }
    }
    bool repear(string s){
        if(s.size()==0){
            return false;
        }
        int next[s.size()];
        getNext(next,s);
        int len=s.size();
        if(next[len-1]!=-1 && len %(len-(next[len-1]+1))==0){
            return ture;
        }
        return false;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值