zoukankan      html  css  js  c++  java
  • KMP算法

    特点

    假定文本串长度为n, 模式串长度为m, 朴素字符串比较时间复杂度为O(n*m),KMP算法时间复杂度为O(n+m)

    朴素算法在匹配失败后重新从首部开始匹配,而KMP则利用模式串本身的特点,在匹配失败时不用每次都从模式串首部开始匹配,
    关键就在于利用模式串的前缀和后缀相同的部分
    比如char[] p = "abdabe", 当p[5] = e匹配失败时,朴素算法是重新从p[0]开始匹配,但通过观察,我们发现p[0,1]和p[3,4]相同,可以从p[3]开始匹配
    这正是KMP的思想,next数组就对应着前面需要的关键观察信息(知道p[0,1] = p[3,4]相同),在这里next[4] = 1;

    计算next数组

    令next[i-1] = k 表示[0, i-1]的最长前缀后缀的索引k(不包括p[0, i]),即p[0, k] = p[i-k-1, i-1]相同
    如何求p[0, i]的最长前缀后缀呢?

    • p[i] == p[k+1], 显然next[i] = k+1
    • p[i] != p[k+1], next[i] < k+1, 这时仍然有p[0, k] = p[i-k-1, i-1]相同, 我们再次在p[0, k]中找到最长前缀后缀,k = next[k], 然后在其后的位置检验

    证明:

    • 若next[i] = k+1, 则p[i] == p[k+1],与题设不符
    • 若next[i] > k+1, 则next[i-1] > k,与题设不符

    还是以上面的例子来说明,根据定义最后一个b位置next[4]=1,

    • 如果e位置能够和d位置匹配,则next[5]=1+1=2很合理
    • 如果e位置不能喝d位置匹配,则问题演化成d之前ab的前缀最长有多少和e之前的ab的后缀重合,这也就是next[2]

    例题

    28. Implement strStr()

    class Solution {
    private:
        vector<int> next;
        void ComputeNext(const string& p){
            int n = p.size();
            next.resize(n);
            
            int k = -1;
            next[0] = k;
            for(int i = 1; i < n; i++){
                while(k > -1 && p[k+1] != p[i]){
                    k = next[k];
                }
                
                if(p[k+1] == p[i]) k++;
                next[i] = k;
            }
        }
        
        
        int KMP(const string &t, const string &p){
            ComputeNext(p);
            int k = -1;
            for(int i = 0; i < t.size(); i++){
                while(k > -1 && p[k+1] != t[i]){
                    k = next[k];
                }
                
                if(p[k+1] == t[i]) k++;
                if(k == p.size() - 1) return i - p.size() + 1;
            }
            
            return -1;
        }
    public:
        int strStr(string haystack, string needle) {
            return needle == "" ? 0 : KMP(haystack, needle);
        }
    };
    
  • 相关阅读:
    关于maven下载速度慢,下载完的依赖包不知去向的应对措施
    进一步解析二分搜索树的实现
    mysql语法建库建表综合整理是示例
    走进二分搜索树的第一课
    优先队列和堆
    window系统mysql安装后获取默认密码
    微信小程序中使用云开发获取openid
    使用IDEA将springboot框架导入的两种方法
    C/C++、Qt4实现FTP客户端(有无界面版)
    云服务器搭建代理服务器 —— 某sock ,简单说明
  • 原文地址:https://www.cnblogs.com/qbits/p/10986489.html
Copyright © 2011-2022 走看看