• 如何理解KMP算法


    KMP算法的核心思想:设法让主串不回退,让子串回退的更少

    整个过程分为两步:

    1. 为子串建立一张最长匹配长度的表
    2. 利用这种表的索引对主串实现匹配判断

    测试样本:

    主串:"fsaabababzabababaaba"
    子串:"abababzabababa"
    

    第一步

    规则:对每个子字符串 [0...i],算出其「相匹配的前缀与后缀中,最长的字符串的长度」。

    例如:

    当i=5时,对子字符串ababab来说
    前缀:a、ab、aba、abab、ababa
    后缀:b、ab、bab、abab、babab
    此时最长匹配长度为4,匹配项为abab,同时其中同时看到另外一个匹配项ab
    

    了解了这张表的来历,那么应该怎样简化运算来求解最后一位a的最长匹配长度呢?

    当i=12时,对子字符串 abababzababab 来说,
    前缀:a, ab, aba, abab, ababa, ababab, abababz, ...
    后缀:b, ab, bab, abab, babab, ababab, zababab, ...
    

    子字符串abababzababab前缀后缀最大匹配了6个(ababab),那次大匹配了多少呢?容易看出次大匹配了4个(abab),更仔细地观察可以发现,次大匹配的前缀后缀只可能在 ababab 中,所以次大匹配数就是 ababab 的最大匹配数!第三大同理,可得abab的最大匹配数,查表可得该值为2。

    ?处找最大匹配发现结尾不是z,所以就不能直接6+1=7,应该找次大匹配,发现刚好对上abab后的字符a,所以?为4+1=5,匹配项为abab

    到此为止,第一步已经完成了

    代码如下:

    // 构造 pattern 的最大匹配数表
    public static int[] calculateMaxMatchLengths(String pattern) {
        int[] maxMatchLengths = new int[pattern.length()];
        int maxLength = 0;
        for (int i = 1; i < pattern.length(); i++) {
            while (maxLength > 0 && pattern.charAt(maxLength) != pattern.charAt(i)) {
                maxLength = maxMatchLengths[maxLength - 1];
            }
            if (pattern.charAt(i) == pattern.charAt(maxLength)) {
                maxLength++;
            }
            maxMatchLengths[i] = maxLength;
        }
        return maxMatchLengths;
    }
    

    第二步

    既然子串的表已经建立,那么下一步就是对主串使用了

    首先,主串是不回退的,所以这里用for循环实现从头到尾的遍历,同时对应寻找子串的最大匹配

    在循环内部分三种情况执行:

    1. 部分匹配成功,指针i和count往后移动
    2. 匹配失败,改变count,寻找次大匹配
    3. 完全匹配成功,记录位置
    public static List<Integer> KMP_search(String text,String pattern){
        List<Integer> positions=new ArrayList<>();
        int[] maxMatchLengths = calculateMaxMatchLengths(pattern);
        int count = 0;
        for (int i = 0; i < text.length(); i++) {
            // charAt() 方法用于返回指定索引处的字符。索引范围为从 0 到 length() - 1。
            while (count > 0 && pattern.charAt(count) != text.charAt(i)) {
                count = maxMatchLengths[count - 1];
            }
            if (pattern.charAt(count) == text.charAt(i)) {
                count++;
            }
            if (count == pattern.length()) {
                // 完全匹配成功时
                positions.add(i - pattern.length() + 1);
                count = maxMatchLengths[count - 1];
            }
        }
        return positions;
    }
    

    好了,到此为止KMP算法的核心已经写完了,下面开始测试:

    public static void main(String[] args) {
        String str= "abababzabababa";
        String text="abbabababzabababac";
        int[] a=Test.calculateMaxMatchLengths(str);
        for (int s:a) {
            System.out.println(s);
        }
        System.out.println(Test.KMP_search(text,str));
    }
    

  • 相关阅读:
    KubernetesConfigMap
    SpringCloudEureka
    KubernetesIngress
    ModuleNotFoundError: No module named 'MySQLdb'
    Django将默认的SQLite更换为MySQL
    Django模板
    如何让他人访问本地启动的django服务
    django.db.utils.OperationalError: no such table: auth_user
    Django 模型字段类型和字段参数总结
    Django模型
  • 原文地址:https://www.cnblogs.com/zhengyu-ahu/p/12421217.html
Copyright © 2020-2023  润新知