《算法笔记》编程笔记——第十二章 字符串专题

《算法笔记》编程笔记——第十二章 字符串专题

  • KMP算法

    • 给出两个字符串,判断其中一个字符串是否是另一个字符串的子串。如果用暴力求解,时间复杂度将达到O(n*m),如果用KMP算法,时间复杂度仅为O(n + m)。

    • next数组

      • int型数组,其中next[i]表示使子串s[0……i]的前缀s[0……k]等于后缀s[i-k……i]的最大的k。(注意前缀跟后缀可以有部分重叠,但是不能是s[0……i]本身);如果找不到相等的前后缀,就令next[i] = -1. 显然,next[i]就是所求最长相等前后缀中前缀的最后一位的下标

      • next数组求解如下图所示,上框为一种方法,下框为另一种方法
        在这里插入图片描述

      • 求解思路:

        ①初始化next数组,令j = next[0] = -1.

        ②让i在1~len-1(len为字符串s长度)范围内遍历,对每个i,执行③④,以求解next[i]。

        ③不断令j = next[j],直到j回退为-1,或是s[i] == s[j+1]成立。

        ④如果s[i] == s[j+1],则next[i] = j+ 1,否则next[i] = j。

      • 代码如下

        //getNext求解长度为len的字符串s的next数组
        void getNext(char s[], int len){
            int j = -1;
            next[0] = -1; //第一步初始化j与next数组
            //第二步,循环
            for(int i = 1; i <= len -1; i++){
                //第三步,j更新
                while(j != -1 && s[i] != s[j+1]){
                    j = next[j];
                }
                //第四步,更新next数组
                if(s[i] == s[j+1]){
                    j++;
                }
                next[i] = j;
            }
        }
        
    • KMP算法

      • 总体思路:当字符串不匹配时,不是让j退回到-1,而是退回到最近的j’,使得text[i] == pattern[j’ + 1]成立并且pattern[0……j’]仍然与text的相应位置处于匹配状态,也就是pattern[0……j’]是pattern[0……j]的最长相等前后缀从这个角度来说,next数组的含义就是当j+1匹配失败时,j应该回退到的位置。

      • 求解具体思路:

        ①初始化j = -1,表示pattern当前已被匹配的最后位。

        ②让i遍历字符串text,对每个i,执行③④来试图匹配text[i]和pattern[j+1]。

        ③不断令j = next[j],直到j回退到-1或者text[i] == pattern[j+1]成立 。

        ④如果text[i] == pattern[j+1],则令j++;如果j达到m-1(m为pattern字字符串的长度),说明pattern是text的子串,返回true。

      • 代码实现

        //KMP算法,判断pattern是否是text的子//KMP算法,判断pattern是否是text的子串
        bool KMP(char text[], char pattern[]){
            int n = strlen(text), m = strlen(pattern);
            getNext(pattern, m);//计算pattern的next数组
            int j = -1;//第一步,初始化
            //第二步,遍历循环
            for(int i = 0; i < n; i++){
                //第三步,j更新
                while(j != -1 && text[i] != pattern[j+1]){
                    j = next[j];//不断回退
                }
                if(text[i] == pattern[j+1])j++;
                //第四步,判断是否完全匹配
                if(j == m-1)return true;
            }
            return false;
        }
        
      • 求解pattern在text中出现的次数。

      • 思路:

        ①当j = m-1时表示pattern的第一次成功完全匹配,此时让记录成功匹配次数的变量加1,然后考虑让j回退到next[j]的位置,继续进行下一次的匹配。

      • 代码实现

        //KMP算法,统计pattern在text中出现的次数
        int KMP(char text[], char pattern[]){
            int n = strlen(text), m = strlen(pattern);
            getNext(pattern);
            int ans = 0, j = -1;//j初始化,ans记录成功匹配次数
            for(int i = 0; i < n; i++){
                while(j != -1 && text[i] != pattern[j+1]){
                    j = next[j];//更新j
                }
                if(text[i] == pattern[j+1])j++;
                //这里是与不统计pattern匹配次数的KMP算法不同的地方。
                if(j == m-1){
                    ans++;
                    j = next[j];
                }
            }
            return ans;
        }
        
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

梦想总比行动多

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

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

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

打赏作者

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

抵扣说明:

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

余额充值