滚动hash实现字符串匹配

滚动哈希:常数时间生成哈希码

生成一个长度为 L 数组的哈希码,需要 O(L) 时间。
如何在常数时间生成滑动窗口数组的哈希码?利用滑动窗口的特性,每次滑动都有一个元素进,一个出。
由于只会出现小写的英文字母,因此可以将字符串转化成值为 0 到 25 的整数数组: arr[i] = (int)S.charAt(i) - (int)‘a’。
按照这种规则,abcd 整数数组形式就是 [0, 1, 2, 3],转换公式如下所示。
h0
可以将上面的公式写成通式,如下所示。其中 ci为整数数组中的元素,a = 26,其为字符集的个数。类似于26进制数转换成10进制数一样。
在这里插入图片描述

下面来考虑窗口从 abcd 滑动到 bcde 的情况。这时候整数形式数组从 [0, 1, 2, 3] 变成了 [1, 2, 3, 4],
数组最左边的 0 被移除,同时最右边新添了 4。滑动后数组的哈希值可以根据滑动前数组的哈希值来计算,
计算公式如下所示。
在这里插入图片描述

写成通式如下所示。
在这里插入图片描述

如何避免溢出:
aL可能是一个很大的数字,因此需要设置数值上限来避免溢出。
设置数值上限可以用取模的方式,即用 h % modulus 来代替原本的哈希值。
hash碰撞问题:
最后如果得到的hash之相同,还要检查子串和目标串是否相同

复杂度分析时间复杂度:
O(N),计算 needle 字符串的哈希值需要 O(L) 时间,之后需要执行 (N−L) 次循环,每次循环的计算复杂度为常数。
空间复杂度:O(1)。

Rabin-Karp算法被称道的三个原因
它可以用来检测抄袭,因为它能够处理多模式匹配;
Rabin-Karp算法能够有效地检测抄袭
虽然在理论上并不比暴力匹配法更优,但在实际应用中它的复杂度仅为O(n+m);
如果能够选择一个好的哈希函数,它的效率将会很高,而且也易于实现。

Rabin-Karp算法被诟病的两个原因
有许多字符串匹配算法的复杂度小于O(n+m);
有时候它和暴力匹配法一样慢,并且它需要额外空间。
结语:
Rabin-Karp算法之所以出众最大的原因就是它可以对多模型进行匹配。
这一特性使得它在检测抄袭方面(尤其是大篇幅文字)非常好用。

package 字符串匹配;

public class 滚动hash {

	public static int strStr(String haystack, String needle) {
        int n = haystack.length(), L = needle.length();
        if(L > n) return -1;
        
        char[] src = haystack.toCharArray(), target = needle.toCharArray();
        int a = 128, h0 = 0, L0 = 0, mod = 1 << 30;
        
        for (int i = 0; i < L; i++) {
			h0 = (h0 * a + src[i]) % mod;
			L0 = (L0 * a + target[i]) % mod;
		}
        if(h0 == L0 && needle.equals(haystack.substring(0, L))) {
        	return 0;
        }
        int al = 1;
        for (int i = 1; i < L; i++) {
        	al = al * a % mod;
		}
        for (int i = L; i < n; i++) {
			h0 = ((h0 - src[i-L] * al) * a + src[i]) % mod;
			if(h0 == L0 && needle.equals(haystack.substring(i - L + 1, i + 1))) {
				return i - L + 1;
			}
		}
        return -1;
    }
	public static void main(String[] args) {
		System.out.println(strStr("3热3火irnr3陈849Irma,0493从da", "rma,"));
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值