KMP算法

作者: leo小超 | 来源:发表于2019-06-23 17:54 被阅读0次

    字符串中找字串索引

    暴破,直接处理从最开始匹配,从0-n开始循环查找,不相等重新计算
    时间复杂度:O(n*m)

    KMP算法处理找字符串中字串索引

    如图:当"ABCDAB "失配时,直接移动到和"AB ABCD"处比较。



    怎么知道移动位置?
    失配处为D,D之前字符串为"ABCDAB",而"ABCDAB" 的前缀匹配为AB,那么"ABCDAB "字符串" "(空格)之前的2为"AB"和需要找的字符串"ABCDABD"的前2为一定相同。如果为0,则直接直接移动到空格处开始比较。
    public Integer indexSubStr(String s, String subStr) {
            int[] f = calculateTable(subStr);
    
            int j = 0;
            for (int i = 0; i < s.length(); ) {
                if (s.charAt(i) == subStr.charAt(j)) {
                    j++;
                    if (j == subStr.length()) {
                        return i - (j - 1);
                    }
                    i++;
                } else {
                    // 第一位没匹配成功,i++继续从j=0即字串第1位开始匹配
                    if (j == 0) {
                       i++;
                    } else {
                        // 有匹配成功的前缀,i不变,对齐匹配成功的前缀
                        // 匹配到"BBC ABCDAB "和"ABCDABD"时," "和"D"不等
                        // 但"D"前缀f[j-1]为2即"AB",i不动继续和"ABCDABD"前缀之后比较,即"BBC ABCDAB "的"AB "和"ABCDABD"的"ABC"比较
                        j = f[j - 1];
                    }
                }
            }
    
            return -1;
        }
    
    
    

    关键计算前缀匹配表算法


    思路
    cacacabc
    caca
      caca
    

    此时匹配成功,匹配+1

    cacacabc
    cacac
      cacab
    

    不匹配找更短的匹配串,cacac和cacab因为不匹配找更短的,即前缀cacac的更短的串caca和cacab更短的串,有相同更短的串caca。caca是已经匹配了的前缀,length = 4,而caca的匹配度等于匹配表中f[4-1]=f(3)位置

    1. 所以cacac匹配失效时,减少1个匹配度,即已经匹配了的caca的匹配度
    2. 如果cacac的串caca无匹配前缀即时匹配为0,表示cacab的前缀串caca无法和当前比较字符串匹配,结束,直接从失配处和子串第一位重新开始匹配;
    3. 如果cacac的caca前缀有匹配,那么假设匹配2位表示cacab和前缀caca也匹配2位即ca,那么比较第三位b和当前比较字符串第三位
    4. 如果匹配则匹配度是3位,即匹配为2+1=3,匹配到cab
    5. 如果不匹配则继续找前缀ca的前缀匹无匹配结束有匹配继续和b比较,如此匹配一直循环下去
    public int[] calculateTable(String subStr) {
            // 计算table
            int[] f = new int[subStr.length()];
            f[0] = 0;
            int t = 0;
            char temp;
            for (int i = 1; i < subStr.length(); i++) {
                temp = subStr.charAt(i);
                if (temp == subStr.charAt(t)) {
                    f[i] = ++t;
                } else {
                    while (t > 0) {
                        // 假设到b不匹配,b之前匹配度为caca即t,t=4
                        // 拿caca继续找匹配度(索引从0开始)t=f[t-1]=f[3]=2,s[t]=s[2]=c≠b
                        // 拿ca继续找t=f[t-1]=f[1]=0匹配度为0结束
                        t = f[t - 1];
                        if (t > 0) {
                            if (temp == subStr.charAt(t)) {
                                f[i] = ++t;
                                break;
                            }
                        }
                    }
                }
            }
            return f;
        }
    

    借鉴

    shortest-palindrome-solution中KMP图解
    KMP算法详解 前面讲移动很清晰,讲计算table不结合KMP图解中的图看更清楚

    相关文章

      网友评论

          本文标题:KMP算法

          本文链接:https://www.haomeiwen.com/subject/aycwqctx.html