【AcWing14】【LeetCode】KMP算法-28/796/214/459

这个博主的图解原理非常好!

https://leetcode.cn/problems/shortest-palindrome/solution/tu-jie-kmpsuan-fa-by-yangbingjie/

这个算法一开始看还真看不明白,收藏这个博主的详细讲解。
(算法)通俗易懂的字符串匹配KMP算法及求next值算法

代码模板

#include <iostream>
using namespace std;

const int N = 1e5 + 10, M = 1e6 + 10;

char s[M], p[N];
int m, n, ne[N];

int main()
{
    //字符从第一个开始读入,你看后面循环也是,i=1,j+1=1,看个人习惯,无所谓
    cin >> n >> p+1;
    cin >> m >> s+1;
    
    for(int i=2,j=0;i<=n;i++)
    {
    	//与后搜索理解类似
        while(j && p[i] != p[j+1]) j = ne[j];
        if(p[i] == p[j+1]) j++;
        ne[i] = j;
    }
    
    //每次比的都是i和j+1
    for(int i=1,j=0;i<=m;i++)
    {
    	//每次没匹配并且还没退到最开始就往回退
        while(j && s[i] != p[j+1]) j = ne[j];
        //匹配了,就往下走一位
        if(s[i] == p[j+1]) j++;
        if(j == n)
        {
            //题意从0开始算下标
            cout << i - n << " ";
            //匹配成功,退一步接着往后看
            j = ne[j];
        }
    }
    return 0;
}

LeetCode 28. 实现strStr()

匹配原理:
1.求str1[i+1]对应的next值,即求str1[0]str1[i]这段的最大公共前后缀。求str1[0]str1[i]的最大公共前后缀,需要遍历str1[0]~str[i - 1]中所有的公共前后缀,直到新元素和前缀的下一位相同即为匹配成功,新的公共最长前后缀的长度即为当前遍历的公共前后缀长度+1,next[i+1]=新的长度+1(next值需要额外加1,原因见下文)。如果遍历完所有的公共前后缀都没有满足条件,则next[i+1]=1, 意味着该位匹配失败得直接从头再来匹配了。(我们将第一位的next值定义为0,意味着如果遍历到了这里,就说明已经遍历完了所有前后缀了,也正是因为如此,我们要将其他元素的next值定义为最长公共前后缀的值+1,其实就是为了区分这个起始的0)

void next(string& str1, vector<int> &next){
    int length = str1.size();
    next.resize(length + 1);
    next[0] = -1; 
    next[1] = 0;
    int i = 1;
    int j = 0;
    while (i < length)
    {
        if(j == 0 || str1[i-1] == str1[j-1]){//当所有公共前后缀都匹配不上或者匹配成功
            next[++i] = ++j;                 //更新next
        }else{
            j = next[j];//遍历下一个可能的公共前后缀
        }
    }
}

作者:hei-xiao-chang-pian
链接:https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/solution/kmp-by-hei-xiao-chang-pian-o6j9/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

代码随想录的题解比acwing的好

链接:https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/solution/dai-ma-sui-xiang-lu-kmpsuan-fa-xiang-jie-mfbs/

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

作者:carlsun-2

来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

LeetCode 796.旋转字符串

class Solution {
public:
    void getNext(string& p, vector<int>& next) {
        int pLen = p.size();
        next.resize(pLen, -1);
        int k = -1, j = 0;
        while (j < pLen - 1) {
            if (k == -1 || p[k] == p[j]) {
                k++;
                j++;
                next[j] = k;
            } else {
                k = next[k];
            }
        }
    }
    bool rotateString(string A, string B) {
        if (A.size() != B.size()) return false;
        A += A;
        int ALen = A.size();
        int BLen = B.size();
        vector<int> next;
        getNext(B, next);
        int i = 0, j = 0;
        while (i < ALen && j < BLen) {
            if (j == -1 || A[i] == B[j]) {
                i++;
                j++;
            } else {
                j = next[j];
            }
        }
        return j == BLen ? true : false;
    }
};

LeetCode 214. 最短回文串

class Solution {
public:
    int commpute_next(string pattern){
        vector<int>next(pattern.size() + 1, 0);
        next[0] = -1;
        next[1] = 0; // 长度为1的字符串没有前后缀
        int i = 2; // i表示next数组的索引
        int k = 0; // 指针指向pattern的位置
        while (i < next.size()) {
            // 如果当前字符匹配成功
            if (pattern[i - 1] == pattern[k]) { // pattern索引比next索引小1
                next[i] = k + 1;
                k = next[i];
                ++i;
            // 如果指针已经指向pattern[0]却还没有匹配成功
            } else if (k == 0){
                next[i] = 0;
                ++i;
            } else{
                k = next[k]; //可以利用已匹配成功的信息,让指针不进行回退,查找next数组
            }
        }
        return next[next.size() - 1]; // 只需要返回最后一个值
    }

    string shortestPalindrome(string s) {
        if(s == ""){
            return "";
        }
        string reverse_str(s.rbegin(), s.rend());
        string pattern = s + '#' + reverse_str;
        int max_len = commpute_next(pattern);
        return reverse_str.substr(0, reverse_str.size() - max_len) + s;
    }
};

作者:yangbingjie
链接:https://leetcode.cn/problems/shortest-palindrome/solution/tu-jie-kmpsuan-fa-by-yangbingjie/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

LeetCode 459. 重复的子字符串-要再思考一下

代码随想录的题解要配上以下kmp详解
https://www.bilibili.com/video/BV1cg41127fw/

http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html

http://www.matrix67.com/blog/archives/115

和这个
https://blank.blog.csdn.net/article/details/80979293

S=S1S2S3
如果最长的公共前后缀是S1S2, 那么重叠的一定是重复的子串,这里一定要理解。反复揣摩什么是公共前后缀。

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

作者:carlsun-2
链接:https://leetcode.cn/problems/repeated-substring-pattern/solution/by-carlsun-2-g3iz/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大大枫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值