字符串匹配 - RK算法

名称来由

RK 算法的全称叫 Rabin-Karp 算法. 它是由两位发明者 Rabin 和 Karp 的名字来命名的算法.

实现思路

BF算法的实现思路是对主串n中的每一个连续子串n1,都与模式串m 进行比较,该算法的复杂度为O(m*n)
RK算法是在BF算法的基础上做了一些改进:通过字符串hash值比较代替字符串的遍历比较。这样能提交字符串的比较效率,但是并没有提高算法的时间复杂度,因为计算每一个连续子串n1的hash值,也是有时间消耗的,跟遍历比较的时间复杂度一样都是O(m),所有子串的hash值的计算时间复杂度为O(mn),那么这样整体的RK算法的时间复杂度还是O(mn),进一步的优化点可以放在hash值的计算上

hash值计算优化思路

如果子串n1的hash值的计算,是通过子串中每个字符计算出的val值做的累加,例如主串abcd,那么子串有abcbcd,假设abc串的hash值为hash(abc),那么bcd串的hash值的计算方式就是hash(bcd) = hash(abc) - val(a) + val(d),这样就可以减少没必要的hash值的重复计算,所有子串的hash值的计算时间复杂度为O(m + (n-m)) = O(n)

还有一个问题就是hash冲突,遇到hash冲突(不同的子串得到相同的hash值)怎么办?

遇到hash冲突,则返回到字符串的遍历比较,来最终确定n1与m是否相同

时间复杂度

O(m+n)

伪代码实现

// ln : 主串的长度,lm:模式串的长度
// hn1 : 子串的hash值,hm:模式串的hash值
// val() : 字符hash值的计算方法
for (i = 0 ; i < lm ; i++) {
	hn1 += val(n[i]);
	hm += val(m[i]);
}
for (i = 0 ; i <= ln - lm ; i++) {
	// 如果hash值相同,则返回去比较字符串
	if (hn1 == hm) {
		if (两个子串相同) {
			return i;
		}
	}
	// 计算下一个子串的hash值
	hn1 += val(n[i + lm +1]);
	hn1 -= val(n[i]);
}

golang实现

func strStr(haystack string, needle string) int {
	needleLen := len(needle)
	if needleLen == 0 {
		return 0
	}
	hlen := len(haystack)
	if hlen < needleLen {
		return -1
	}

	// 计算第一个子串和模式串的hash值
	subHaystackHash, needleHash, step, stepMax := 0, 0, 26, 1
	for i := 0; i < needleLen; i++ {
		subHaystackHash = (step*subHaystackHash + int(haystack[i]-'a'))
		needleHash = (step*needleHash + int(needle[i]-'a'))
		if i > 0 {
			stepMax *= step
		}
	}
	idx := -1
	for i, _ := range haystack {
		if i+needleLen > hlen {
			break
		}

		// 如何hash值相同而且子串与模式串相同
		if subHaystackHash == needleHash && isMatch(haystack, needle, i) {
			idx = i
			break
		} else {
			// 计算下一个子串hash值
			subHaystackHash = (subHaystackHash-int(haystack[i]-'a')*stepMax)*step + int(haystack[i+needleLen]-'a')
			continue
		}
	}
	return idx
}

// 字符串匹配
func isMatch(haystack string, needle string, idx int) bool {
	for i2, _ := range needle {
		if idx+i2 >= len(haystack) || haystack[idx+i2] != needle[i2] {
			return false
		}
	}
	return true
}

总结

作为一个字符串匹配的算法,通过hash值预先匹配,从而加快匹配的效率,这确实是一个不错的解决思路,但是该算法的弊端也很明显,那就是需要设计一个可以匹配各类字符串的算法,这个并不容易实现,如果hash算法实现不好,算法的时间复杂度就会进行退化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值