代码随想录字符串及KMP总结

一.什么是串

串:零个或多个字符组成的有限序列,字符是串的元素,字符长度为n时为空串,而空白串指的是由一个或多个空格组成的串

子串:任意连续字符组成的子序列,空串也是子串

串的储存结构:数组,链串

二.替换数字

        预先给数组扩容,再从后向前遍历,s.resize(n)可扩容

三.翻转字符串里的单词

class Solution {
public:
    void removeExtraSpaces(string&s){
        int slow = 0;
        for(int i = 0;i<s.size();++i){
            if(s[i]!=' '){     
 //这段相当于一个大前提,就是后面的代码只care非空字符,空格都当没看见哎,都自己加
                if(slow!=0){s[slow++] =' ';}
//这段代码第一次循环肯定不执行,一定是读了一个单词以后自己加的空格
                while(i<s.size()&&s[i]!=' '){
                    s[slow++] = s[i++];
                }
            }
        }
        s.resize(slow);//相当于把结尾的空格删了

    }

    string reverseWords(string s) {
        removeExtraSpaces(s);
        reverse(s.begin(),s.end());
        int start = 0;
        for(int i = 0;i<=s.size();++i){
            if(i==s.size() ||s[i] ==' '){
                reverse(s.begin()+start,s.begin()+i);
                //这句一定是在读取完一个单词的逆置后执行的,i就相当于单词尾部
                start = i+1;
            }
        }
        return s;

    }
};

四.KMP
class Solution {
public:
    void computeNextArray(const string &s, vector<int> &next) {
        int m = s.size();
        int i = 1, j = 0;
        next[0] = -1; // 初始化第一个位置为 -1

        while (i < m) {
            if (j == -1 || s[i] == s[j]) {
                ++i;
                ++j;
                next[i] = j; // 填充 next 数组
            } else {
                j = next[j]; // 在模式串中回溯
            }
        }
    }

    int strStr(string haystack, string needle) {
        if (needle.size() == 0) {
            return 0; // 如果 needle 为空,返回 0
        }

        int n = haystack.size();
        int m = needle.size();
        vector<int> next(m + 1);
        computeNextArray(needle, next);

        int i = 0, j = 0; // 初始化两个指针
        while (i < n && j < m) {
            if (j == -1 || haystack[i] == needle[j]) {
                ++i;
                ++j;
            } else {
                j = next[j];
            }
        }
        if (j == m) {
            return i - j; // 匹配成功,返回起始索引
        }

        return -1; // 没有匹配项,返回 -1
    }
};

        上述代码是一个经典的求KMP的问题,下面我们来逐步讲解一下这个有点难以理解的代码

        不论是叫next数组也好,还是PMT表,或前缀表,首先给你一个字符串。那么从0号元素开始,依次取1,2,3...个元素构成子列,对于任意一个子列而言,一个由前缀构成的集合,一个由后缀构成的集合。前缀从0开始,后缀从子列最后一个元素开始,前后缀分别形成两个集合。而两个集合中肯定有相同的元素,这个表就是用来记录两个集合中最长的相等元素。例如,当集合取5个元素时,对于字符串”ababa”,它的前缀集合为{”a”, ”ab”, ”aba”, ”abab”},它的后缀集合为{”baba”, ”aba”, ”ba”, ”a”}, 两个集合的交集为{”a”, ”aba”},其中最长的元素为”aba”,长度为3。对称不是中心对称,而是中心字符块对称,比如不是abccba,而是abcabc这种对称。那么对于任意一个字符串·,我们都可以对齐建立一个这样统计字符前后关系的一个表。

        而KMP算法的第一步就是对所求串建立一个这样的表,那么该如何建立next数组呢?

void computeNextArray(const string &s, vector<int> &next) {
        int m = s.size();
        int i = 1, j = 0;
        next[0] = -1; // 初始化第一个位置为 -1

        while (i < m) {
            if (j == -1 || s[i] == s[j]) {
                ++i;
                ++j;
                next[i] = j; // 填充 next 数组
            } else {
                j = next[j]; // 在模式串中回溯
            }
        }
    }

        以一个函数处理next表,参数为string和·一个动态数组next,以下图为例,j表示前缀,i表示后缀,next[0]数组为-1,所以我们将i预制为1,j预制为0。

 while (i < m) {
            if (j == -1 || s[i] == s[j]) {
                ++i;
                ++j;
                next[i] = j; // 填充 next 数组
            } 
        }
    


            这个循环就是在建立原串的next表,如果处于起始阶段或前后字符是一样的,前后缀指针都向后移一个单位,next数组中的值表示前后缀相同元素的个数。              

nk
基本思路

        建立了模式串的next数组后,我们现在就用next数组来简化查找过程。

 简化查找

int i = 0, j = 0; // 初始化两个指针
        while (i < n && j < m) {
            if (j == -1 || haystack[i] == needle[j]) {
                ++i;
                ++j;
            } else {
                j = next[j];
            }
        }
        if (j == m) {
            return i - j; // 匹配成功,返回起始索引
        }

        return -1; // 没有匹配项,返回 -1
    }
};

      

  

        现在基本的代码逻辑应该比较清晰,现在讨论一下为什么他可以简化查找。要知道,这个算法本身就是在排除可能性,他就是对字符串前后有重复序列的好使,如果完全不一样,其实BF算法甚至比他还省事儿。但对于一个有重复序列的来说,他的意思是,如果我的模式串不是在开头,那么就在中间或结尾,如果咱两要匹配,最起码得有一部分是相同的的吧,那通过next表,我就知道如果你这里不匹配,哪里还有部分匹配的,省去了从一个匹配的都没有的开始找。

本文部分观点和理解以及图片来源于以下up和博主

@yearn520

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/yearn520/article/details/6729426


@海纳
链接:https://www.zhihu.com/question/21923021/answer/281346746
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

@B站up“正月点灯笼”
https://www.bilibili.com/video/BV1Px411z7Yo?from=search&seid=13225444196686531503
https://www.bilibili.com/video/BV1hW411a7ys/?spm_id_from=333.788.videocard.0

@B站懒猫

懒猫老师-数据结构-(15)KMP算法2-next数组(模式匹配,字符串匹配)_哔哩哔哩_bilibili

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值