• 记个笔记 KMP 复杂难用 too big to fails


    现在回过头来看觉得没什么难度,但是刚开始看的时候看那些直接套用公式的代码,完全没法理解(专家盲点(Curse of knowledge))(感谢这个博主七年前的帖子)把next[]数组讲明白,但是发现自己也很难给别人讲明白 。先记录下自己思考的笔记,看看能不能渡有缘人

    但是,对比起Sunday等其他搜索算法,真的觉得KMP几个巧妙的步骤真的复杂而没有必要。。建议直接sunday

    KMP

    BBCXABCDABXBCDABCDABDE
    ABCDABD

    X处失败时,返回上一位,前缀后缀最长公共元素长度AB=2,即从后缀AB处再开始对比,直接从开始X与C对比

    模式串 A B C D A B D
    前缀后缀最长公共元素 0 0 0 0 1 2 0
    next[] -1 0 0 0 0 1 2

    next[] 便于查找时判断子串从前往后是否有重复项

    KMP的关键也就是建next[]数组:

    ​ 往后遍历

    ​ 先判断j是否与第一个元素相同

    ​ 标记&next[j+1]=1

    ​ 判断第二个元素...

    private void getNext(String p, int next[]) {
                int len = p.length();
                int i = 0;
                int j = -1;
                next[0] = -1;//这个默认的,
    
                while (i < len - 1) {
                    if (j == -1 || p.charAt(i) == p.charAt(j)) {
    
                        i++;
                        j++;
                        next[i] = j;
                    } else
    
                        j = next[j];//restart from head
                }
            }
    

    例子

    母串H [i]

    子串N [j]

    回退next[]

    i,j 从头开始比较,当H[i]!=N[j],如例子中i=10,j=6

    向右移动子串j-next[j]=4

    BBCXABCDABXBCDABCDABDE
    ABCDABD

    并且继续从i处开始比较(j=next[j]=2),...右移...☞匹配

     public int strStr(String haystack, String needle) {
                if (needle.length() == 0)
                    return 0;
                int i = 0;
                int j = 0;
    
                int[] next = new int[needle.length()];
                getNext(needle, next);
                while (i < haystack.length() && j < needle.length()) {
    
                    if (j == -1 || haystack.charAt(i) == needle.charAt(j)) {
                        i++;
                        j++;
                    } else {
    
                        j = next[j]; // j回到指定位置
                    }
                    if (j == needle.length())
                        return i - j;
                }
                return -1;
            }
    
  • 相关阅读:
    el-table——可编辑拖拽转换csv格式的表格
    【C#进阶系列】25 线程基础
    【C#进阶系列】24 运行时序列化
    【C#进阶系列】23 程序集加载和反射
    【C#进阶系列】22 CLR寄宿和AppDomain
    【C#进阶系列】21 托管堆和垃圾回收
    【C#进阶系列】20 异常和状态管理
    【C#进阶系列】19 可空值类型
    【C#进阶系列】18 特性Attribute
    【C#进阶系列】17 委托
  • 原文地址:https://www.cnblogs.com/impw/p/15578890.html
Copyright © 2020-2023  润新知