KMP算法

字符串中找字串索引

暴破,直接处理从最开始匹配,从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算法)