学习两种字符串匹配算法BF算法和RK算法

问题
给你两个字符串A和B,请你判断B是否是A的子串,并且返回B在A中第一次出现的位置。
示例1:
A:abcdefg
B:cde
return 2;
示例2:
A:abcdefg
B:acg
return -1;

解决方式1:BF算法(Brute Force,暴力算法)
示例:
A:abcdefg
B:cde
第一步:把B的首位字母©和A首位字母(a)比较,两者并不匹配
第二步:把B的首位字母©和A第二位字母(b)比较,两者并不匹配
第三步:把B的首位字母©和A第三位字母©比较,两者匹配
第四步:把B的第二位字母(d)和A第四位字母(d)比较,两者匹配

由此得到结果,模式串 cde 是主串 abcdefg的子串,在主串第一次出现的位置下标是 2。
优点:能解决问题
缺点:在某些极端情况下算法效率非常低
例如:
A:aaaaaaaaaaaaaaaaaab
B:aaab
上述情况,在每一轮进行字符匹配时,B的前三个字符a都和A中的字符相匹配,一直检查到B最后一个字符b,才发现不匹配,这样一来,两个字符串在每一轮都需要白白比较4次,显然非常浪费。
假设主串的长度是m,模式串的长度是n,那么在这种极端情况下,BF算法的最坏时间复杂度是O(mn)。

更优方案:RK算法(由算法两位发明者Rabin和Karp的名字命名的)
BF算法只是简单粗暴对两个字符串中的所有字符串依次比较,RK算法比较两个字符串的hash值。RK算法的核心思想类似于hash函数。对于hash函数有了解的同学应该知道,我们通过hash函数可以将一个字符串映射成一个数字(hash值)。当两个字符串的hash值不相同时,说明这两个字符串一定不匹配,而相同时则说明两个字符串是有可能匹配的,那么就需要进一步验证。
代码如下

	public static int rabinKarp(String str, String pattern) {
		// 主串长度
		int m = str.length();
		// 模式串的长度
		int n = pattern.length();
		// 计算模式串的hash值
		int patternCode = hash(pattern);
		// 计算主串当中第一个和模式串等长的子串hash值
		int strCode = hash(str.substring(0, n));
		// 用模式串的hash值和主串的局部hash值比较。
		// 如果匹配,则进行精确比较;如果不匹配,计算主串中相邻子串的hash值。
		for (int i = 0; i < m - n + 1; i++) {
			if (strCode == patternCode && compareString(i, str, pattern)) {
				return i;
			}
			// 如果不是最后一轮,更新主串从i到i+n的hash值
			if (i < m - n) {
				strCode = nextHash(str, strCode, i, n);
			}
		}
		return -1;
	}

	private static int hash(String str) {
		int hashcode = 0;
		// 这里采用最简单的hashcode计算方式:
		// 把a当做1,把b当中2,把c当中3.....然后按位相加
		for (int i = 0; i < str.length(); i++) {
			hashcode += str.charAt(i) - 'a';
		}
		return hashcode;
	}

	private static int nextHash(String str, int hash, int index, int n) {
		hash -= str.charAt(index) - 'a';
		hash += str.charAt(index + n) - 'a';
		return hash;
	}

	private static boolean compareString(int i, String str, String pattern) {
		String strSub = str.substring(i, i + pattern.length());
		return strSub.equals(pattern);
	}

	public static void main(String[] args) {
		String str = "aacdesadsdfer";
		String pattern = "adsd";
		System.out.println("第一次出现的位置:" + rabinKarp(str, pattern));
	}
	

缺点:当哈希冲突过多,RK算法需要逐个比较,RK算法就退化成了BF算法。

更优的算法如KMP,Sunday等算法,自行了解。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
字符串匹配算法是一种用来查找一个字符串(即目标串)在另一个字符串(即模式串)中的出现位置的算法。其中,KMP算法是一种比较常用的字符串匹配算法。 KMP算法的核心思想是通过利用模式串中已经匹配过的信息,来尽量减少目标串和模式串的比较次数,从而提高匹配效率。它利用一个最长公共前缀和最长公共后缀数组,记录模式串中已经匹配成功的前缀和后缀的长度。通过根据这些信息来移动模式串的位置,避免不必要的比较。 而字符串哈希算法是一种将字符串映射为一个较短的固定长度的数值的算法。通过对字符串的每个字符进行一系列运算,如求幂、取模等,最终得到一个哈希值。这个哈希值可以代表该字符串的特征,不同字符串的哈希值一般不会相同。 字符串哈希算法的主要作用是将字符串转化为一个定长的数字,方便在数据结构中进行比较和存储。在字符串匹配中,使用哈希算法可以将目标串和模式串转换为哈希值,然后比较哈希值是否相等来判断是否匹配。由于比较哈希值的时间复杂度较低,使用字符串哈希算法可以提高匹配效率。 总的来说,字符串匹配算法和字符串哈希算法都是用来处理字符串匹配的问题。KMP算法通过利用已知信息来减少比较次数,提高匹配效率;而字符串哈希算法则是将字符串转化为哈希值,便于进行比较和存储。两者都在一定程度上提高了字符串匹配的效率。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值