【C++】 【滚动哈希】【Rolling Hash】字符串匹配算法问题; Rabin-Karp 算法;哈希思想;哈希与哈希冲突处理;

目录

  • 前言
  • 一、问题引入 - 字符串匹配 - 滚动哈希
  • 二、滚动哈希 - Rabin-Karp 算法
  • 三、复杂度分析与优劣分析
  • 四、代码
    • 1、测试
  • 参考

前言

哈希是一个思想,将字符串看成高进制的数指,求出其哈希值,用其哈希值解决问题。

使用滚动哈希来求解字符串匹配问题就是 Rabin-Karp 算法;

一、问题引入 - 字符串匹配 - 滚动哈希

其实就是因为暴力法要重复计算好多子问题。那么用哈希来算,就只需要每次选头和尾。

1147. 段式回文

字母转成哈希 整形然后取模,不等就直接不用判断,相等在判断哈希冲突的情况。

1392. 最长快乐前缀

暴力法->超时;

暴力法+哈希预处理;√ 就是所谓的 Rabin-Karp 算法? □

实际上这个题m取得好不会产生哈希冲突,但是最好还是处理一下哈希冲突,因为毕竟是学习,不是讨巧。

187. 重复的DNA序列

我直接用stl 的hash map存string做了;就是暴力法

将其看成4进制进行手动哈希;因为不用求余,不存在哈希冲突。

二、滚动哈希 - Rabin-Karp 算法

根据上面的题。我们同样可以根据待匹配字符串的哈希值去匹配整个字符串。

推广开来,一般化:

【C++】 【滚动哈希】【Rolling Hash】字符串匹配算法问题; Rabin-Karp 算法;哈希思想;哈希与哈希冲突处理;_第1张图片

其中加上模再取模是因为:每次求解都有取模,所以造成:(减去头部字符串*进制) 的结果成为负数,所以加一个模数再取模可以让其再转回正数。

其实就是时钟的思想:三点之前的八小时是几点。其实就是七点;这里模数为12;
【C++】 【滚动哈希】【Rolling Hash】字符串匹配算法问题; Rabin-Karp 算法;哈希思想;哈希与哈希冲突处理;_第2张图片

三、复杂度分析与优劣分析

相对于暴力求解的O(mn)的复杂度来说在很多情况下都快了很多。

尤其是在极端用例下:aaa…b (1000个a)去匹配aaaa…b(10万个a);这样的极端用例将会慢的要死。O(mn)

但是在最平常的使用,可能还会慢于暴力法。因为做了很多大数操作。但是极端情况下,滚动哈希很难会退化。

【C++】 【滚动哈希】【Rolling Hash】字符串匹配算法问题; Rabin-Karp 算法;哈希思想;哈希与哈希冲突处理;_第3张图片

劣势:不能用于求解一个字符串中,多个匹配的位置。因为也会退化成为O(mn);如下例,不同的匹配成功,然后处理哈希冲突。使得其性能退化

于是引出KMP算法。
【C++】 【滚动哈希】【Rolling Hash】字符串匹配算法问题; Rabin-Karp 算法;哈希思想;哈希与哈希冲突处理;_第4张图片

四、代码


int isequal(string& s, string& t,  int index)
{
	for (auto it : t)
		if (s[index++] != it) return false;

	return true;

}
int Rolling_Hash(string& s, string& t)
{
	if (s.size() < t.size()) return -1;
	if (t.size() == 0) return 0;

	long long hash_t = 0, MOD = (long)1e9 + 7, B = 256; //hash  mod  进制
	for (int i = 0; i < t.size(); i++)
		hash_t = (hash_t*B+ t[i]) % MOD;

	long long  hash_cur = 0, position = 1;
	for (int i = 0; i < t.size() - 1; i++) //最高位的权重。
		position = position * B %MOD;
	for (int i = 0; i < t.size() - 1; i++) //前端哈希值
		hash_cur = (hash_cur*B + s[i]) % MOD;

	for (int i = t.size() - 1; i < s.size(); i++)//计算开始
	{
		hash_cur = (hash_cur*B+ s[i]) % MOD;
		if (hash_cur == hash_t && isequal(s, t, i - t.size() + 1))
			return i - t.size() + 1;

		hash_cur = (hash_cur - s[i - t.size() + 1] * position %MOD+ MOD) % MOD;

	}
	return -1;
}

1、测试

void main()
{
	string s = "i love hdu or not";
	string t1 = "love";
	string t2 = " love";
	string t3 = " hdu";
	string t4 = "or";

	cout << Rolling_Hash(s, t1)<<endl;
	cout << Rolling_Hash(s, t2)<<endl;
	cout << Rolling_Hash(s, t3)<<endl;
	cout << Rolling_Hash(s, t4)<<endl;
} 

在这里插入图片描述

参考

bobo老师github

解决哈希冲突;动态哈希表;哈希思想

你可能感兴趣的:(c/c++,数据结构与算法,算法,哈希,字符串)