KMP

简介

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth、J.H.Morris和V.R.Pratt提出,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。

实现

构造 next[] 数组

  • 前缀:除最后一个字符外,字符串的所有头部子串

  • 后缀:除第一个字符外,字符串的所有尾部子串

  • 前后缀相等的最大长度:$\{a, ab, aba\} \cap \{b, ab, bab\}=\{ab\}$

  • next[i]:模式串 s[0...i-1] 的相等前后缀的最大长度

字串 前缀 后缀 相等前后缀的最大长度
"" $\phi$ $\phi$ next[0] = -1
"a" {} {} next[1] = 0
"ab" {"a"} {"b"} next[2] = 0
"aba" {"a", "ab"} {"a", "ba"} next[3] = 1
"abab" {"a", "ab", "aba"} {"b", "ab", "bab"} next[4] = 2

匹配

求解 next[] 数组

代码

public class Solution
{
    public static void solution(String s1, String s2)
    {
        ArrayList<Integer> ans = new ArrayList<>();
        int[] next = getNext(s2);
        int i = 0, j = 0;
        while (i < s1.length())
        {
            if (s1.charAt(i) == s2.charAt(j))
            {
                i++;
                j++;
            }
            else if (next[j] == -1) i++;
            else j = next[j];
            if (j == s2.length())
            {
                ans.add(i - j);
                j = 0;
            }
        }
        if (!ans.isEmpty())
            System.out.println(ans.stream().map(String::valueOf).collect(Collectors.joining(" ")));
        else
            System.out.println(-1);
    }

    public static int[] getNext(String s)
    {
        if (s.length() == 1) return new int[]{-1};
        int[] next = new int[s.length()];
        int pos = 2, cn = 0;
        next[0] = -1;
        next[1] = 0;
        while (pos < s.length())
        {
            if (s.charAt(pos - 1) == s.charAt(cn))
                next[pos++] = ++cn;
            else if (cn > 0)
                cn = next[cn];
            else
                next[pos++] = 0;
        }
        return next;
    }

    public static void main(String[] args)
    {
        solution("ababcabaababac", "ababa");
    }
}
posted @ 2023-12-08 18:57  Vivid-BinGo  阅读(11)  评论(0编辑  收藏  举报