ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

459. 重复的子字符串(KMP算法)

2021-09-20 12:33:22  阅读:157  来源: 互联网

标签:459 相同 后缀 算法 KMP fail 长度 now 最长


459. 重复的子字符串

image-20210920114930823

优秀解法:KMP(n,n)

  • fail数组定义:最长前后缀长度-1 如ababab为3 最长前后缀为4:abab(第一个) abab(第二个)

  • 初始值为什么为-1:让第一个if的now + 1 = 0 否则会少判断第一个字母

  • 怎么加速获得fail值:

    • 如果s[now + 1] == s[i] 即在最长前缀的后一个字母也和当前串下一个字母相同 那么当然最长前后缀长度加一

    image-20210920115542617

    • 如果不相等 那么仍可利用原来的最长前后缀

      我们当然不想把这个长度缩小太多 因为我们要找的是最长相同前缀后缀 那么这个前缀必定会在子串A 后缀必定会在子串B(因为这两个子串完全相同)

      同时 因为子串A的后缀与子串B的后缀相同 那么新最长相同前后缀长度等于子串A的最长相同前后缀长度 即 now = fail[now - 1](fail数组定义为最长相同前后缀长度的情况,下面的代码定义为长度-1所以有所不同),当终于P[now] = P[x]则可以向右扩展 或者始终不相等则从零开始

      image-20210920115847937

class Solution {
public:
    bool kmp(const string& s){
        int n = s.size();
        //将fail定义为最长相同前后缀长度 - 1  
        vector<int> fail(n,-1);
        for(int i = 1; i < n; i++){
            int now = fail[i - 1];
            //如果初始值是-1 那么这里是now + 1 如果是0 这里是now 下面的赋值同理
            while(now != -1 && s[now + 1] != s[i]){
                //如果始终不同 那么始终缩短为a串的最长相同子前缀直到now为-1或者相同了
                now = fail[now];
            }
            //前一个fail值的下一位和当前位相同的话 当前fail为前fail+1
            if(s[now + 1] == s[i]) fail[i] = now + 1;
        } 
        //第一个条件:只有当原串有相同前后缀才有可能符合题意
        //第二个条件:规律:最长规律字串长度 = n - 最长前后缀 成倍数 
        return fail[n - 1] != -1 && n % (n - fail[n - 1] - 1) == 0;        
    }

    bool repeatedSubstringPattern(string s) {
        return kmp(s);
    }

    
};

参考资料:知乎KMP回答

标签:459,相同,后缀,算法,KMP,fail,长度,now,最长
来源: https://blog.csdn.net/Rush6666/article/details/120389968

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有