串的模式匹配(二)---KMP算法

改进的模式匹配算法

KMP算法的优点:主串不回溯。

KMP算法的时间复杂度为O(m+n)

字符串的前缀:除最后一个字符以外,所有头部子串。
字符串的后缀:除第一个字符以外,所有尾部子串。
PM数组是部分匹配值,部分匹配值是字符串的前缀和后缀的最长相等前后缀长度。
以abca举例:
‘a’,前后缀均为空集,即最长相等前后缀长度为0;
‘ab’,前缀是{ a },后缀是{ b },最长相等前后缀长度是0;
‘abc’,前缀是{ a, ab },后缀是{ c, bc },最长相等前后缀长度是0;
‘abca’,前缀是{ a, ab, abc },后缀是{ a, ca, bca },最长相等前后缀长度是1;

表1 PM表

编号1234
Tabca
PM0001

我们使用部分匹配值(PM)主要是为了求解移动位数

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

而next数组是由PM数组右移然后加一所得。

表2 next表

编号1234
Tabca
next0111
public class StringMatching {	
	//计算next数组
	static void get_next(char T[], int next[]) {
		int i=1,j=0;
		while(i<T.length) {
			if(j == 0 || T[i] == T[j]) {
				
				i++;
				j++;
				next[i]=j;
				
			}else {
				j=next[j];
			}
				
		}
		
	}
	//KMP匹配算法
	static int Index_KMP(char S[], char T[], int next[]) {
		int i=1,j=1;
		//get_next(T,next);
		while(i<S.length && j<T.length) {
			if(j == 0 || S[i] == T[j]) {
				i++;j++;
			}else
				j=next[j];
		}
		if(j>=T.length)
			return i-T.length;
		else
			return 0;
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String S = "cdababcadfgh";
		String T = "abca";
		int next[]=new int[20];//初始化next数组
		get_next(T.toCharArray(),next); //next值
		System.out.println("next数组:");
		for(int i=1;i<=T.length();i++) {
			System.out.print(next[i]+" ");
		}
		System.out.println();
		int id = Index_KMP(S.toCharArray(),T.toCharArray(),next);
		if(id == 0) {
			System.out.print("匹配失败!");
		}else {
			System.out.print("匹配成功!字符串T在字符串S的第"+id+"的位置。");
		}
		
	}

}

其实一般情况下,暴力匹配的实际执行时间近似为KMP,因此暴力匹配至今仍被采用,但在主串与子串有许多“部分匹配”的时候,KMP算法就明显速度快于暴力匹配算法

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

傻猴儿

小编,多谢客官留下的赏钱。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值