字符串匹配之KMP算法

给定一个字符串和一个文本,在文本中找出这个字符串的位置。

最直接的解法是暴力遍历字符串。时间复杂度是o(n*m)

暴力解法:

      字符串,文本从头开始一个一个字符串匹配,当字符串中和文本中字符不匹配,开始回溯到文本这一个开始比较位置的下一个字符和字符串开始字符串比较。知道遍历完文本,或者找出匹配的位置。

暴力解法时间复杂度高。

下面介绍字符串匹配KMP算法。

      KMP算法是经典的字符串匹配算法,它的时间复杂度是O(n), 核心思想是回溯移动比较字符串索引,不移动匹配字符串的索引。一般情况,匹配的字符串很长,远远大于比较字符串的长度。

     和暴力算法不同,KMP算法额外生成一个next数组,这个数组就是 字符串不匹配时,下一次比较字符的索引位置,而不移动回溯匹配字符串位置。大大降低了时间复杂度。

先来看一下草图:(next数组根据比较字符串计算出来的)

如图,索引为4时B和E不匹配,根据KMP的思想,来看下一步怎么比较的。 如下图所示

如上图直接移动的"ABABE"匹配字符串的索引,在比较。移动的规则在于next数组,当上一步索引为4是不匹配,求next[4] = 2,

索引直接设置"ABABE"的索引为2,在和索引为4 的比较字符串匹配。

就这样直到字符串匹配成功为止。上面匹配开始索引为12

 

分解步骤求"ABABE"的next数组:

next数组的求解,索引0,1初始为-1,0,cn = 0。 

索引为index = 2时,比较索引index - 1 和cn 位置字符串,设置为cn。

索引index = 3 时, 比较索引index - 1 和cn 位置字符串,相等cn = cn + 1 ,设置next[index] = cn

索引index = 4 时,比较索引index-1和cn位置字符串,相等cn = cn + 1, 设置next[index] = cn

代码:

	public int[] getNextArray(char[] ms) {
		if (ms.length == 1) {
			return new int[] { -1 };
		}
		int[] next = new int[ms.length];
		next[0] = -1;
		next[1] = 0;
		int pos = 2;
		int cn = 0;
		while (pos < next.length) {
			if (ms[pos - 1] == ms[cn]) {
				next[pos++] = ++cn;
			} else if (cn > 0) { //调整cn ,如果不加判断,那么next数组后面都趋向一个数
				cn = next[cn]; 
			} else {
				next[pos++] = cn;
			}
		}
		return next;
	}

思想是求不匹配字符前的首尾相同字符串的长度。

KMP算法代码:

public int getIndexOf(String s, String m) {
		if (s == null || m == null || m.length() < 1 || s.length() < m.length()) {
			return -1;
		}
		char[] ss = s.toCharArray();
		char[] ms = m.toCharArray();
		int si = 0;
		int mi = 0;
		int[] next = getNextArray(ms);
		while (si < ss.length && mi < ms.length) {
			if (ss[si] == ms[mi]) {
				si++;
				mi++;
			} else if (next[mi] == -1) {
				si++;
			} else {
				mi = next[mi];
			}
		}
		return mi == ms.length ? si - mi : -1;
	}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值