KMP

KMP

[找出字符串中第一个匹配的下标]( 28. 找出字符串中第一个匹配项的下标 - 力扣(LeetCode) )

KMP算法核心:利用匹配失败后的信息尽量减少模式串与主串的匹配次数以达到快速匹配的目的

首先了解字符串的前缀与后缀 对于串:ababacb

  • 真前缀集合是
  • 真后缀集合是

如何减少匹配次数呢?

我们将i指针保持不变,指针j回到有可能匹配成功的位置

只回溯指针j,不回溯指针i

1669541384845 1669541405817

思路

因为aba在前面的就已经匹配过了,当且仅当A子串的后缀集合与B子串的前缀集合有交集时,将B串后移到指针i之前的这一段才能成功匹配

B串要移动多少位呢?或者说j指针要回溯到哪个位置?

我们要在已获得的信息中做到不遗漏的同时尽可能多的匹配,于是我们要找到A子串的后缀集合与B子串的前缀集合的交集里最长的那个元素,这个最长的元素才能使B串后移的最少且在已知信息中匹配的最多,这个最长元素的长度就是j指针回溯的位置,从那个位置往后和i指针之后的字符再开始匹配

同时我们可以发现A子串和B子串是相同的,因为它们都是经过匹配才留下来的,所以A子串的后缀集合与B子串的前缀集合的交集完全可以改为B子串的前缀集合与它本身的后缀集合的交集,j指针回溯的位置 =B子串的最长公共前后缀 通过隐藏信息,匹配失败时A串与B串存在着一段相同的子串,j指针回溯的位置只与B串有关,与A串无关

所以我们可以在A,B字符串匹配之前就通过B串计算出回溯位置,存在一个数组next里,next与 B串形成映射数组,存的数据next[i]就是B[0]~B[i]的最长公共前后缀的长度

快速构建next数组

next[i]就是B[0]~B[i]的最长公共前后缀的长度

  • B串自己与自己匹配,B[0]--B[i]的前缀与它的后缀匹配,后缀为主串,前缀为模式串,以递推的方式求出next数组,目的是求出B[0]--B[i]的最长公共前后缀的长度

  • 如果匹配,next[i]=j+1,j是B串的前缀指针,也就是当前字符匹配之前的最长公共前后缀的长度,匹配成功了,所以要加1

  • 如果不匹配,回溯j指针,j=next[j],直到匹配成功

    注: i 指针在 j 指针后面,i可以从1开始,单个字符没有真前缀与真后缀

1669542554492

next数组的构建其实就是左右指针移动的过程

1669542632884 1669542648454

后续操作基本都是重复上述步骤,当指针 i 到达最后一个字符时

1669542669456
public static void getNext(String B) {
		int[] next = new int[B.length()];
		for(int i=1,j=0;i<B.length();i++) {
			while(j>0&&B.charAt(i)!=B.charAt(j)) {//不相同且j大于0,j指针回溯
				j=next[j-1];
			}
			if(B.charAt(i)==B.charAt(j)) {//相同,i指针,j指针同时后移(i指针的移动在for循环里)
				j++;
			}
			next[i]=j;//存储前缀与后缀的最长公共子串长度(这个时候j已经在原有的基础上加1了,除非j=0)
		}
	}

A,B字符串匹配的步骤(主串与模式串的匹配步骤)

  • i,j初始化为0
  • 如果A[i+1] == B[j+1],i++,j++继续匹配
  • 如果A[i+1] != B[j+1],j指针回溯到next[j](前提时j>0),直到A[i+1] = B[j+1],当j==0时且不满足 A[i+1] == B[j+1],忽略j,i++直到A[i+1] == B[j+1]
  • j==B串的长度时,说明找到了匹配位置
	//字符串匹配
	public static int kmp(String A,String B) {
		for(int i=0,j=0;i<A.length();i++) {
			while(j>0&&A.charAt(i)!=B.charAt(j)) {//j=0时,只考虑移动i指针直到A.charAt(i)==B.charAt(j)

				j=next[j-1];//j指针回溯
			}
			if(A.charAt(i)==B.charAt(j)) { //单个字符匹配成功,i指针与j指针前移
				j++;
			}
			if(j==B.length()) {
				return i-j+1;  //返回第一个匹配项的下标
			}
		}
		return -1;  //没有匹配项返回-1
	}
posted @   QING~h  阅读(53)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示

目录导航