美文网首页
左神算法笔记——KMP算法

左神算法笔记——KMP算法

作者: yaco | 来源:发表于2020-04-08 12:52 被阅读0次

介绍

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度。参考——百度百科

题目

LeetCode28. 实现 strStr()

给定两个字符串,查找一个字符串是否包含另一个字符串,如果包含,返回该字符串的起始下标

思路分析

  • 首先理清变量,假设从str1字符串中查找str2字符串是否存在以及存在的起始位置。

解法一: 暴力枚举,遍历str1的每个字符的位置,依次比对两个字符相应位置的字符,如果str2字符串的指针走到了最后,则表示当前匹配成功,返回当前str1的其实位置

解法二: KMP算法

  • 首先获取一个关于str2的记录每个位置最长公共前后缀的数组,记为preNextArr。
  • preNextArr的具体含义:在当前位置之前所有字符构成的字符串中,头部和尾部完全一样的字符串长度,前缀不包括最后一个字符,后缀包括第一个字符。
  • 遍历str1数组,如果遍历到str2的某个位置发现 str1[i] 不等于 str2[i], 则跳转到preNextArr数组中记录的位置继续比较。

暴力枚举代码

class Solution {
    
    // 暴力解法
    public int strStr(String haystack, String needle) {
        // 首先进行边界条件判断
        if(haystack == null || needle == null || haystack.length() < needle.length()){
            return -1;
        }
        if("".equals(needle)) return 0;
        char[] charH = haystack.toCharArray();
        char[] charN = needle.toCharArray();
        for(int i = 0; i + charN.length - 1 < charH.length; i++){
            int ch = i;
            int cn = 0;
            while(cn < charN.length && charH[ch] == charN[cn]){
                ch++;
                cn++;
            }
            if(cn == charN.length){
                return i;
            }
        }
        return -1;
    }
}

KMP算法

    // KMP 算法主体
    public static int getIndexOf(String s, String m) {
        // 首先进行边界条件的判断,如果有一个为空,或者s长度小于m, 则一定无法匹配,直接返回-1
        if (s == null || m == null || m.length() < 1 || s.length() < m.length()) {
            return -1;
        }
        // 将s和m改造为字符数组
        char[] ss = s.toCharArray();
        char[] ms = m.toCharArray();
        // 创建两个指针进入while循环,si表示s的索引,mi表示m的索引
        int si = 0;
        int mi = 0;
        int[] next = getNextArray(ms);
        // 结束条件是si和mi其中有一个遍历完了整个字符数组
        while (si < ss.length && mi < ms.length) {
            if (ss[si] == ms[mi]) {
                // 决策一:如果当前s和m位置的元素相等,则两个指针均向后面移动
                si++;
                mi++;
            } else if (next[mi] == -1) {
                // 决策二: 如果不相等,且此时m位于字符数组的起始位置,那么直接将s向后移
                si++;
            } else {
                // 决策三; 如果不想等,但此时的m不在起始位置,则s不懂, m调正到next【mi】的位置继续向相面比较
                mi = next[mi];
            }
        }
        // 等到循环结束时,s和m一定有一个已经全部遍历完了,如果时m遍历完了,则找到了m,否则返回-1
        return mi == ms.length ? si - mi : -1;
    }

    // 给定一个字符串的字符数组,返回一个数组表示每个元素之前字符串的最长公共前后缀,0位置默认-1,1位置默认0;
    public static int[] getNextArray(char[] ms) {
        // 如果数组只有一个元素,默认返回-1;
        if (ms.length == 1) {
            return new int[] { -1 };
        }
        // 创建一个数组,默认和原始数组等长,使得每个位置的元素信息都可以知道
        int[] next = new int[ms.length];
        // 初始化0和1位置上的元素
        next[0] = -1;
        next[1] = 0;
        // 给定两个变量pos和cn进入while循环,pos表示当前元素的位置,cn表示当前元素前面一位的元素最长公共前后缀(就是前面那一位的next[pos - 1])
        int pos = 2;
        int cn = 0;
        while (pos < next.length) {
            if (ms[pos - 1] == ms[cn]) {
                // 如果前面一位元素与前缀的后一位相等,则next【pos】再前一位的cn基础上+1
                next[pos++] = ++cn;
            } else if (cn > 0) {
                // 如果不相等的话,那么cn指向前缀的后面一位,继续进入循环,此处pos没有进行自增操作,还是在原来的位置
                cn = next[cn];
            } else {
                // 此处如果cn == 0 ,则表示前一位的最长公共前后缀不存在,而且此时,mas[pos - 1] != ms[cn] ,则此位置的公共前后缀也一定为0
                next[pos++] = 0;
            }
        }
        // 返回结果集next数组
        return next;
    }

    public static void main(String[] args) {
        String str = "abcabcababaccc";
        String match = "ababa";
        System.out.println(getIndexOf(str, match));
    }

相关文章

  • 左神算法笔记——KMP算法

    介绍 KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,...

  • 对KMP算法的一些理解

    最近学到KMP算法,下面讲讲对KMP算法的一些个人理解,希望对大家有帮助! 对于KMP算法的理解: 整个KMP算法...

  • KMP 专题整理

    KMP 学习记录 kuangbin专题十六——KMP KMP 学习总结 朴素 KMP 算法 拓展 KMP 算法(E...

  • 串的模式匹配算法

    KMP算法 算法匹配

  • KMP算法文章合集

    字符串的查找:朴素查找算法和KMP算法 暴力匹配算法与KMP算法(串的匹配) 字符串查找算法BF和KMP 字符串匹...

  • 字符串匹配

    BF 算法和 RK 算法BM 算法和 KMP 算法

  • KMP算法——寻找子串位置

    KMP算法——寻找子串位置 1、KMP算法简介: KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J....

  • 字符串匹配 - KMP算法

    前面我们介绍非常高效的 BM 算法,今天我们介绍另一个非常出名且高效的 KMP 算法。 KMP 算法思想 KMP ...

  • 算法笔记-KMP算法

    整理了一下据说由于过于晦涩难懂而导致某系统程序猿直接在实现字符串匹配的时候直接用暴力算法代替的KMP算法,初看之时...

  • KMP 算法

    KMP 算法 1. 暴力匹配算法 在分析KMP算法前, 先看看暴力匹配算法是如何工作的.暴力匹配算法的基本思想是:...

网友评论

      本文标题:左神算法笔记——KMP算法

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