KMP算法(用于字符串匹配)

leetcode题源:实现strStr()

KMP算法的讲解

给定一个text字符串,和一个pattern字符串,找出pattern字符串在text字符串中开始的位置,如果不能匹配到,则返回-1;

       在使用普通的双指针进行匹配时,如果匹配失败,则text指针要回到匹配开始位置的下一位置再进行下一轮匹配,如果两个字符串包含大量重复的字符,则这种回退大部分是不必要的。时间复杂度:O((n-m)*m),n是text的长度,m是pattern的长度

  KMP通过引入一个next数组来记录pattern指针可以回退的位置,使text指针不需要回退。时间复杂度:O(m+n)

例如:

text:    [a, b, e, a, b, a, b, e, a, b, f]

pattern: [a, b, e, a, b, f]

next:     [0, 0, 0, 1, 2, 0] 

next数组的含义和如何构造是关键

class Solution {
    public int strStr(String haystack, String needle) {
        // 暴力解法,边界条件太麻烦,O((n-m)*m)的时间复杂度
        int len1 = haystack.length();
        int len2 = needle.length();
        if(len2==0) return 0;
        int p=0;
        for(int q=0; q+len2<=len1; q++){  // 这里要进行优化处理,否则时间复杂度为O(nm)
            if(haystack.charAt(q)==needle.charAt(0)){
                p = q;
                boolean flag = true;
                for(int i=0; i<len2; i++){
                    if(needle.charAt(i)!=haystack.charAt(q+i)){
                        flag = false;
                        break;
                    }
                }
                if(flag) return p;
            }
        }
        return -1;

        // KMP算法: 如果已经匹配的字符串包含相同的前缀和后缀,遇到下一个不匹配的位置时,指向needle的指针跳转到前缀的后一个位置,
     // 不匹配的话,再回退后继续比较;先构造一个next数组来记录needle指针跳转的位置
int n=haystack.length(), m=needle.length(); if(m==0) return 0; // 先构造next数组,next数组中的元素表示当前两个元素不匹配时,needle指针要跳转的位置 // needle: [a, b, e, a, b, f] // next: [0, 0, 0, 1, 2, 0] int[] next = new int[m]; for(int i=1,j=0; i<m; i++){ while(j>0 && needle.charAt(i)!=needle.charAt(j)) j = next[j-1]; // 一直和前一位置的值比较,直到遇到相等的字符或者j=0;j通过next[j-1]来回退 if(needle.charAt(i)==needle.charAt(j)) j++; next[i] = j; } // 利用next数组进行跳转匹配,不再需要回退haystack的指针 for(int i=0,j=0; i<n; i++){ // 匹配不成功,needle指针回退并继续比较 while(j>0 && haystack.charAt(i)!=needle.charAt(j)) j = next[j-1]; if(haystack.charAt(i)==needle.charAt(j)) j++; if(j==m) return i - m + 1; } return -1; } }

 

posted @ 2021-09-08 21:07  菠萝机  阅读(50)  评论(0编辑  收藏  举报