首页 > 编程语言 >kmp算法(Java)

kmp算法(Java)

时间:2022-11-18 17:23:32浏览次数:61  
标签:AB 匹配 前缀 int next 后缀 算法 kmp Java

详解参考: KMP算法讲解



next 数组求法



方式1


移动位数 = 已匹配的字符数 - 对应的部分匹配值

image-20221118170911715

已知空格与D不匹配时,前面六个字符"ABCDAB"是匹配的。查表可知,最后一个匹配字符B对应的"部分匹配值"为2,因此按照下面的公式算出向后移动的位数:
移动位数 = 已匹配的字符数 - 对应的部分匹配值
因为 6 - 2 等于4,所以将搜索词向后移动4位。

image-20221118170927977

因为空格与C不匹配,搜索词还要继续往后移。这时,已匹配的字符数为2("AB"),对应的"部分匹配值"为0。所以,移动位数 = 2 - 0,结果为 2,于是将搜索词向后移2位。

image-20221118170938283



"前缀"和"后缀"。 "前缀"指除了最后一个字符以外,一个字符串的全部头部组合;"后缀"指除了第一个字符以外,一个字符串的全部尾部组合。
 "部分匹配值"就是"前缀"和"后缀"的最长的共有元素的长度。以"ABCDABD"为例,

  - "A"的前缀和后缀都为空集,共有元素的长度为0;

  - "AB"的前缀为[A],后缀为[B],共有元素的长度为0;

  - "ABC"的前缀为[A, AB],后缀为[BC, C],共有元素的长度0;

  - "ABCD"的前缀为[A, AB, ABC],后缀为[BCD, CD, D],共有元素的长度为0;

  - "ABCDA"的前缀为[A, AB, ABC, ABCD],后缀为[BCDA, CDA, DA, A],共有元素为"A",长度为1;

  - "ABCDAB"的前缀为[A, AB, ABC, ABCD, ABCDA],后缀为[BCDAB, CDAB, DAB, AB, B],共有元素为"AB",长度为2;

  - "ABCDABD"的前缀为[A, AB, ABC, ABCD, ABCDA, ABCDAB],后缀为[BCDABD, CDABD, DABD, ABD, BD, D],共有元素的长度为0。




  • 解决指针不回溯


public class Main {
    public static void main(String[] args) {
        String s="abaabcba";
        char[] array = s.toCharArray();
        int i = s.length();
//        System.out.println(Arrays.toString(getNext(s)));
        System.out.println(kmpSearch("ababcddbut","cd"));
    }
    /**
     * O(m+n)
     * @param s 目标串
     * @param p 模式串
     * @return 如果匹配成功,返回下标,否则返回-1
     */
    private static int kmpSearch(String s, String p) {
        int sLen = s.length();
        int pLen = p.length();
        if (sLen < pLen) {
            return -1;
        }
        int[] next = getNext(p);
        int i = 0, j = 0;
        while (i < sLen && j < pLen) {
            if (j == -1 || s.charAt(i) == p.charAt(j)) {
                i++;
                j++;
            } else {
                j = next[j];
            }
        }
        System.out.println(i+"-----"+j);
        return j==pLen?i-j:-1;
    }
    /**
     *  k是前缀,i是后缀,如果不等,就k=next[k],前缀往前移
     * @param p 匹配串(字串)
     * @return
     */
    private static int[] getNext(String p) {
        int len = p.length();
        int[] next = new int[len+1];
        next[0] = -1;
        int i=0,k=-1;
        while (i<len){
            if (k==-1||p.charAt(i)==p.charAt(k)){
                k++;
                i++;
                next[i]=k;
            }else {
                k=next[k];
            }
        }
        return next;
    }
}



方式2



class Solution {
    // KMP 算法
    // ss: 原串(string)  pp: 匹配串(pattern)
    public int strStr(String ss, String pp) {
        if (pp.isEmpty()) return 0;
        
        // 分别读取原串和匹配串的长度
        int n = ss.length(), m = pp.length();
        // 原串和匹配串前面都加空格,使其下标从 1 开始
        ss = " " + ss;
        pp = " " + pp;

        char[] s = ss.toCharArray();
        char[] p = pp.toCharArray();

        // 构建 next 数组,数组长度为匹配串的长度(next 数组是和匹配串相关的)
        int[] next = new int[m + 1];
        // 构造过程 i = 2,j = 0 开始,i 小于等于匹配串长度 【构造 i 从 2 开始】
        for (int i = 2, j = 0; i <= m; i++) {
            // 匹配不成功的话,j = next(j)
            while (j > 0 && p[i] != p[j + 1]) j = next[j];
            // 匹配成功的话,先让 j++
            if (p[i] == p[j + 1]) j++;
            // 更新 next[i],结束本次循环,i++
            next[i] = j;
        }

        // 匹配过程,i = 1,j = 0 开始,i 小于等于原串长度 【匹配 i 从 1 开始】
        for (int i = 1, j = 0; i <= n; i++) {
            // 匹配不成功 j = next(j)
            while (j > 0 && s[i] != p[j + 1]) j = next[j];
            // 匹配成功的话,先让 j++,结束本次循环后 i++
            if (s[i] == p[j + 1]) j++;
            // 整一段匹配成功,直接返回下标
            if (j == m) return i - m;
        }

        return -1;
    }
}

标签:AB,匹配,前缀,int,next,后缀,算法,kmp,Java
From: https://www.cnblogs.com/rain-me/p/16903905.html

相关文章

  • java构造方法的作用
    构造方法作用就是对类进行初始化。如果你没有定议任何构造方法的形式,程式会为你取一个不带任何参数的构造函数,那么你产生类的对像时只能用不带参数的方法,如:classa{}//没......
  • C++不知算法系列之集结常规算法思想
    1.前言数据结构和算法是程序的2大基础结构,如果说数据是程序的汽油,算法则就是程序的发动机。什么是数据结构?指数据之间的逻辑关系以及在计算机中的存储方式,数据的存储......
  • JavaScript代码是怎么在浏览器里面运行起来的?
    JavaScript代码是怎么在浏览器里面运行的?下面简单探索一下浏览器内核浏览器内核(RenderingEngine),常见的叫法如:排版引擎、解释引擎、渲染引擎,现在流行称为浏览器内核。......
  • JavaScript_对象_RegExp2与JavaScript_对象_RegExp3
    JavaScript_对象_RegExp2正则对象:1.创建 1.varreg  =new RegExp(“正则表达式”);2.var......
  • java 文件读写操作
    一、BufferedWriter写入文件+BufferedReader读取文件缓冲字符(BufferedWriter)是一个字符流类来处理字符数据。不同于字节流(数据转换成字节),你可以直接写字符串,数组或字符......
  • 顺序表应用3:元素位置互换之移位算法
    顺序表应用3:元素位置互换之移位算法TimeLimit:1000MSMemorylimit:570K题目描述一个长度为len(1<=len<=1000000)的顺序表,数据元素的类型为整型,将该表分成两半,前一半有m......
  • 顺序表应用2:多余元素删除之建表算法
    顺序表应用2:多余元素删除之建表算法TimeLimit:3MSMemorylimit:600K题目描述一个长度不超过10000数据的顺序表,可能存在着一些值相同的“多余”数据元素(类型为整型),编写一......
  • JavaScript_对象_Math与JavaScript_对象_RegExp1
    JavaScript_对象_MathMath:数学1.创建特点:Math对象不用创建,直接使用。Math.方法名();2.方法random()返回0~1之间的随机数含0不含......
  • Java 8 Stream基础操作汇总
    Java8Stream操作汇总目录Java8Stream操作汇总1.分组2.分组统计3.分组求和4.最大最小值5.排序前提条件://User实体类@DatapublicclassUser{/**......
  • 怎样学算法?
    回答前,我们先来举个例子:如何实现“把大象装进冰箱”? 先来看看丹丹老师的“算法”: 说,要把大象装冰箱,总(long)共分几步?三步。第一步,把冰箱门打开,第二步,把大象装进去,......