KMP算法

硅谷探秘者 6958 0 1

1.PMT

        KMP算法的核心,是一个被称为部分匹配表(Partial Match Table)的数组。我觉得理解KMP的最大障碍就是很多人在看了很多关于KMP的文章之后,仍然搞不懂PMT中的值代表了什么意思。先来解释一下这个数据到底是什么。对于字符串“abababca”,它的PMT如下表所示:

image.png

就像例子中所示的,如果待匹配的模式字符串有8个字符,那么PMT就会有8个值。

        解释一下字符串的前缀和后缀。如果字符串A和B,存在A=BS,其中S是任意的非空字符串,那就称B为A的前缀。例如,”Harry”的前缀包括{”H”, ”Ha”, ”Har”, ”Harr”},我们把所有前缀组成的集合,称为字符串的前缀集合。同样可以定义后缀A=SB, 其中S是任意的非空字符串,那就称B为A的后缀,例如,”Potter”的后缀包括{”otter”, ”tter”, ”ter”, ”er”, ”r”},然后把所有后缀组成的集合,称为字符串的后缀集合。要注意的是,字符串本身并不是自己的后缀。

        有了这个定义,就可以说明PMT中的值的意义了。PMT中的值是字符串的前缀集合与后缀集合的交集中最长元素的长度。例如,对于”aba”,它的前缀集合为{”a”, ”ab”},后缀 集合为{”ba”, ”a”}。两个集合的交集为{”a”},那么长度最长的元素就是字符串”a”了,长 度为1,所以对于”aba”而言,它在PMT表中对应的值就是1。再比如,对于字符串”ababa”,它的前缀集合为{”a”, ”ab”, ”aba”, ”abab”},它的后缀集合为{”baba”, ”aba”, ”ba”, ”a”}, 两个集合的交集为{”a”, ”aba”},其中最长的元素为”aba”,长度为3。

2.PMT的实现

package problem;

public class PMT {
	public static void main(String[] args) {
		int []a=pmt("ababaaababa");
		for(int b:a){
			System.out.print(b+" ");
		}
	}
	//PMT中的值是字符串的前缀集合与后缀集合的交集中最长元素的长度
	public static int[] pmt(String pattern){
	    int[] pmt = new int[pattern.length()];
	    int ml = 0;
	    for (int i = 1; i < pattern.length(); i++) {
	        while (ml > 0 && pattern.charAt(ml) != pattern.charAt(i)) {
	            ml = pmt[ml - 1];
	        }
	        if (pattern.charAt(i) == pattern.charAt(ml)) {
	            ml++;
	        }
	        pmt[i] = ml;
	    }
	    return pmt;
	}
}

3.匹配方法实现

/*
	 * kmp
	 */
	public static List<Integer> kmp(String text, String pattern){
	    List<Integer> positions = new ArrayList<>();
	    int[] pmt = pmt(pattern);
	    int count = 0;//count指向模式串
	    for (int i = 0,k=text.length(); i <k ; i++) {//i指向主串
	        while (count > 0 && pattern.charAt(count) != text.charAt(i)) {//失配
	            count = pmt[count - 1];//模式串指向前缀最有可能匹配的位置
	        }
	        if (pattern.charAt(count) == text.charAt(i)) {//匹配,指针向前走
	            count++;
	        }
	        if (count == pattern.length()) {//匹配成功
	            positions.add(i - pattern.length() + 1);
	            count = pmt[count - 1];//寻找下一匹配位置
	        }
	    }
	    return positions;
	}

4.代码实现:

package KMP;

import java.util.ArrayList;
import java.util.List;

public class PMT {
	public static void main(String[] args) {
		List<Integer> b=kmp("acbabac","ac");
		for(Integer a:b){
			System.out.println(a);
		}
	}
	//PMT中的值是字符串的前缀集合与后缀集合的交集中最长元素的长度
	//前缀函数(失配函数)
	public static int[] pmt(String pattern){
		
	    int[] pmt = 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 = pmt[maxLength - 1];
	        }
	        if (pattern.charAt(i) == pattern.charAt(maxLength)) {
	            maxLength++;
	        }
	        pmt[i] = maxLength;
	    }
	    return pmt;
	}
	/*
	 * kmp
	 */
	public static List<Integer> kmp(String text, String pattern){
	    List<Integer> positions = new ArrayList<>();
	    int[] pmt = pmt(pattern);
	    int count = 0;//count指向模式串
	    for (int i = 0,k=text.length(); i <k ; i++) {//i指向主串
	        while (count > 0 && pattern.charAt(count) != text.charAt(i)) {//失配
	            count = pmt[count - 1];//模式串指向前缀最有可能匹配的位置
	        }
	        if (pattern.charAt(count) == text.charAt(i)) {//匹配,指针向前走
	            count++;
	        }
	        if (count == pattern.length()) {//匹配成功
	            positions.add(i - pattern.length() + 1);
	            count = pmt[count - 1];//寻找下一匹配位置
	        }
	    }
	    return positions;
	}
}



评论区
请写下您的评论...
暂无评论...
猜你喜欢
数据结构与算法 1442 java使用欧几里得比例的方 publicstaticvoidmain(String[]args){ System.out.println(bili(2,6
official 1267 《操作系统》先来先服务(FCFS,FirstComeFirstServe)思想:主要从“公平”的角度考虑(类似于我们生活中排队买东西的例子)规则:按照作业/进程到达的先后顺序进行服务用于作业
weblog 5786 a*搜索动态演示分析请参考http://photo.jiajiajia.club/item/a-star.html什么是a*搜索A*搜寻,俗称A星,作为启发式搜索中的一种,这是一
数据结构与算法 9536 问题描述思路:斐波那契数列的变体考虑如果把20190324项的每一项的值都出来的话,那么值的范围就会超出基本数据类型能够表示的范围,又考虑到题目是求最后四位数,而加时前一位不会影响后一位的计
数据结构与算法 1497 最小生成树和其应用什么是最小生成树:一个有n个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有n个结点,并且有保持图连通的最少的边。最小生成树可以用kruskal(克鲁斯卡尔)
java基础 1471 java并发编程-理解CAS1.什么是cas?CAS:CompareandSwap,即比较再交换。jdk5增加了并发包java.util.concurrent.*,其下面的类使用CAS
数据结构与算法 2251 ; publicNode(intvalue,Nodenext){ super(); this.value=value; this.next=next; }}实现packageclub.test;/***
数据结构,算法基础 424 [数据结构与] 一、简介二、实现初始化FindUnion三、图示四、优化启发式合并路径压缩五、小结一、简介wiki上关于并查集的简介 在计机科学中,并查集是一种树型的数据结构,用于处
归档
2018-11  12 2018-12  33 2019-01  28 2019-02  28 2019-03  32 2019-04  27 2019-05  33 2019-06  6 2019-07  12 2019-08  12 2019-09  21 2019-10  8 2019-11  15 2019-12  25 2020-01  9 2020-02  5 2020-03  16 2020-04  4 2020-06  1 2020-07  7 2020-08  13 2020-09  9 2020-10  5 2020-12  3 2021-01  1 2021-02  5 2021-03  7 2021-04  4 2021-05  4 2021-06  1 2021-07  7 2021-08  2 2021-09  8 2021-10  9 2021-11  16 2021-12  14 2022-01  7 2022-05  1 2022-08  3 2022-09  2 2022-10  2 2022-12  5 2023-01  3 2023-02  1 2023-03  4 2023-04  2 2023-06  3 2023-07  4 2023-08  1 2023-10  1 2024-02  1 2024-03  1 2024-04  1
标签
算法基础 linux 前端 c++ 数据结构 框架 数据库 计算机基础 储备知识 java基础 ASM 其他 深入理解java虚拟机 nginx git 消息中间件 搜索 maven redis docker dubbo vue 导入导出 软件使用 idea插件 协议 无聊的知识 jenkins springboot mqtt协议 keepalived minio mysql ensp 网络基础 xxl-job rabbitmq haproxy srs 音视频 webrtc javascript
目录
没有一个冬天不可逾越,没有一个春天不会来临。最慢的步伐不是跬步,而是徘徊,最快的脚步不是冲刺,而是坚持。