zoukankan      html  css  js  c++  java
  • KMP算法分析

    1、问题出现

    给出一个字符串为source,和另一个字符串target。

    如果这个target是source的字串,返回这个子串的开始的索引。如果不是子串则返回-1。

    2、解决问题的思路

    任何一个算法都说从暴力法优化得到的,KMP算法也不例外。这次我们列出暴力法如下:

     1 public class KMP {
     2     public static int match(String source,String target) {
     3         int i=0;//原字符串的下标
     4         int j=0;//目标子串的下标
     5         int k=-1;//记录第几个字符
     6         while(i<source.length()) {
     7             while(j<target.length()&&source.charAt(i)==target.charAt(j)) {
     8                 i++;
     9                 j++;
    10             }//子串和目标串进行匹配
    11             k++;//首字符位置每次循环后+1。
    12             if(j==target.length()) {
    13                 return k;
    14             }else {
    15                 j=0;
    16                 i=k+1;
    17             }
    18             
    19         }
    20         return -1;
    21     }
    22     public static void main(String[] args) {
    23         System.out.println(match("abababca","bab"));
    24     }
    25 }
     

    这个算法有俩层循环嵌套显得十分臃肿。这时候就需要对算法进行优化。

    3、KMP算法的引入

    上面的算法每次匹配失败之后,我们会都移动i和j。

    而KMP则只需要我们每次只移动需要匹配的字串的j 不移动原字符串的i。这样就少了一层循环。

    那j需要移动到哪呢?KMP为原字符串准备了个next数组。

    先不用管如何实现的。我们先试试这个方法。

    public class KMP2 {
        static int[] next = {-1,0,0,1,2,3,4,0};
        public static int match(String source,String target){
            int i=0;
            int j=0;
            
            while(i<source.length()) {
                if(j == -1 ||source.charAt(i)==target.charAt(j)) {
                    i++;
                    j++;
                }
                else {
                    j=next[j];//这里我们只给j赋值
                }
                if(j==target.length()) {
                    return i-j;//返回匹配开头的字符
                }
            }
            return -1;
        }
        public static void main(String[] args) {
            System.out.println(match("abababca","bab"));
        }
    }

    结果是一样的。这就少了一层循环。

    4、NEXT数组如何求的呢?

    总共分4步骤

    1、找字符串的前缀式:例如 aba这个 前缀式就是a、ab

    2、找字符串的后缀式:例如 aba这个字符串的后缀式为ba、a

    3、找前后俩个字符串相同的最长字串、的长度,这里的aba中a相同,因此就是1

    但是如果未找出就得0;

    如上所示。

    4、把我们之前求的数,向右移。一位就是next数组了。

    此图像的alt属性为空;文件名为@W6IAKAKJ855TKGFEKOZ7.png

    如果之前没做过的,一定要手动算一下。算完了就记住了。

    5、算法求出NEXT数组。

    算法实现是个难理解的地方。

    记住俩概念:索引值为0和1的俩个数设为-1和0,不为什么。记住

    public class KMP2 {
        //static int[] next = {-1,0,0,1,2,3,4,0};
        public static int[] getNext(String source)
        {
            int[] next = new int[source.length()];
            // 初始条件
            int j = 0;
            int k = -1;
            next[0] = -1;
            // 根据已知的前j位推测第j+1位
            while (j <source.length() - 1){
                if (k == -1 || source.charAt(j) ==source.charAt(k)){
                    next[++j] = ++k;
                }
                else{
                    k = next[k];
                }
            }
             return next;
        }
        
        
        public static int match(String source,String target){
            int i=0;
            int j=0;
            int[] next = getNext(source);
            while(i<source.length()) {
                if(j == -1||source.charAt(i)==target.charAt(j)) {
                    i++;
                    j++;
                }
                else {
                    j=next[j];
                }
                if(j==target.length()) {
                    return i-j;
                }
            }
            return -1;
        }
        public static void main(String[] args) {
            System.out.println(match("abababca","bab"));
        }
    }

  • 相关阅读:
    java文件下载
    java程序运行原理
    java io流(核心:读进来,写出去)
    oracle操作表和字段的sql复习
    深入理解C/S和B/S模式
    Windows PyCharm永久激活
    MacBook PyCharm永久激活
    百度云同同步盘 mac版
    SJW-遍历我的账户左侧导航页面(句柄切换)
    python-selenium无法调用浏览器的问题==
  • 原文地址:https://www.cnblogs.com/godoforange/p/10834703.html
Copyright © 2011-2022 走看看