首页 > 编程语言 >字符串匹配——哈希算法

字符串匹配——哈希算法

时间:2024-02-18 20:13:30浏览次数:30  
标签:ah al 算法 哈希 text 字符串 mod

一、算法原理

我们不直接比较字符串 \(S\) 的字串和模式串 \(T\) 是否相等,而是比较二者的哈希值。
设字符串 \(S\) 的长度为 \(l\),字符串 \(T\) 的长度为 \(m\)。
取两个互素的常数 \(b\) 和 \(h\) (\(l < b < h\)),设字符串 \(C = c_1c_2...c_m\),则哈希函数为:

\[H(C)=(c_1b^{m-1}+c_2b^{m-2}+...+c_mb^0) \text~{mod}~h \]

其中 \(b\) 是哈希基数,相当于把字符串看作 \(b\) 进制数(,哈希函数就是将 \(b\) 进制转换为十进制)。

滚动哈希:这是一种优化技巧,用于优化字符串的匹配。
字符串 \(S\) 从下标 \(k + 1\) 开始的长度为 \(m\) 的子串,它的哈希值为 \(H(S[k + 1, k + m])\);字符串 \(S\) 从下标 \(k\) 开始的长度为 \(m\) 的子串,它的哈希值为 \(H(S[k, k + m - 1])\)。二者的关系为:

\[H(S[k + 1, ..., k + m]) = (H(S[k, k + m - 1]) \times b - s_kb^m + s_{k + m})~\text{mod}~h \]

证明:

\[\begin{split} H(S[k + 1, ..., k + m])&=(s_{k+1}b^{m-1}+s_{k+2}b^{m-2}+...+s_{k+m}b^0) \text~{mod}~h\\ \\ H(S[k, k + m - 1])&=(s_kb^{m-1}+s_{k+1}b^{m-2}+...+s_{k+m-1}b^0) \text~{mod}~h \\ H(S[k, k + m - 1]) \times b&=(s_kb^{m}+s_{k+1}b^{m-1}+...+s_{k+m-1}b^1) \text~{mod}~h \\ H(S[k, k + m - 1]) \times b - s_kb^m + s_{k + m}&=(s_{k+1}b^{m-1}+s_{k+2}b^{m-2}+...+s_{k+m}b^0) \text~{mod}~h\\ \\ \therefore H(S[k + 1, ..., k + m]) = (H(S[k, &k + m - 1]) \times b - s_kb^m + s_{k + m})~\text{mod}~h \end{split} \]


二、代码

typedef unsigned long long ull;

const ull B = 1e9 + 7;

// 计算字符串a的哈希值 
ull h(string a)
{
	ull ah = 0;
	for (int i = 0; i < a.size(); i++)    ah = ah * B + a[i];
	return ah;
}

// a是否在b中出现 
bool locate(string a, string b)
{
	// a比b长,a不可能在b中 
	int al = a.size(), bl = b.size();
	if (al > bl)    return false;
	
	// 计算B的al次方
	ull t = 1;
	for (int i = 0; i < al; i++)     t *= B;
	
	// 计算a和b长度为al的前缀对应的哈希值
	ull ah = 0, bh = 0;
	ah = h(a), bh = h(b); 
	
	// 右移窗口,更新哈希值并判断
	if (bh == ah)    return true;
	for (int i = 1; i + al < bl; i++)
	{
		bh = bh * B + b[i + al] - b[i] * t;
		if (bh == ah)    return true;
	}
	return false;
}

注:

  • 这里哈希基数为素数 1e9 + 7,它还有一个孪生素数 1e9 + 9

标签:ah,al,算法,哈希,text,字符串,mod
From: https://www.cnblogs.com/hoyd/p/18019876

相关文章

  • day28 回溯算法part4 代码随想录算法训练营 90. 子集 II
    题目:90.子集II我的感悟:只要功夫深,铁树也开花参考答案,没我写的好理解难点:去重代码难点:i-1的含义易错点:nums要排序回溯要写i+1path.append要添加的是nums[i]代码示例:classSolution:defsubsetsWithDup(self,nums:List[int])->List[List[int]]:......
  • 代码随想录算法训练营第二十天 | 236. 二叉树的最近公共祖先 , 501.二叉搜索树中的众
      530.二叉搜索树的最小绝对差 已解答简单 相关标签相关企业 给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 。差值是一个正数,其数值等于两值之差的绝对值。 示例1:输入:root=[4,2,6,1,3]输出:1示......
  • 第四章 字符串
    目  录第四章、字符串521.创建字符串对象52用一对单引号或者双引号创建字符串52使用str()函数创建字符串53使用转义字符532.索引与切片56索引56切片573.使用+和*运算符60使用+运算符拼接字符串60使用*运算符重复字符串61使用in运算符614.使用字......
  • PWN学习之格式化字符串及CTF常见利用手法
    格式化字符串的基本漏洞点格式化字符串漏洞是一种常见的安全漏洞类型。它利用了程序中对格式化字符串的处理不当,导致可以读取和修改内存中的任意数据。格式化字符串漏洞通常发生在使用C或类似语言编写的程序中,其中 printf、sprintf、fprintf 等函数用于将数据格式化为字符串......
  • 数据结构 —— 串 KMP算法
    串很有意思,就是我们认知的String 1.蛮力算法,就是子串一个一个字符对比。 2.KMP算法时间复杂度O(m+n)关键问题在于构造,Next数组。但是,理解到KMP算法的前后缀重叠,还是比较快的。基本思想是,如果目前的字母不匹配,我往前挪动几个字母,可以匹配到一致的?然后把这个距离记下......
  • 2024牛客寒假算法基础集训营2
    C.TokitsukazeandMin-MaxXOR题解:01Trie观察后发现对序列\(a\)排序并不影响结果然后容易知道,对于\(i<j,a_i\oplusa_j\leqk\),一共有\(2^{i-j-1}\)种序列\(b\)满足条件,特别的,如果\(i=j\),只有\(1\)种满足条件那么现在问题就转换为,我们固定\(a_......
  • 代码随想录算法训练营第十九天 | 98.验证二叉搜索树, 700.二叉搜索树中的搜索,617.合并
     654.最大二叉树 已解答中等 相关标签相关企业 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:创建一个根节点,其值为 nums 中的最大值。递归地在最大值 左边 的 子数组前缀上 构建左子树......
  • 代码随想录算法训练营第十八天 | 112. 路径总和,113. 路径总和ii ,106.从中序与后序遍
     513.找树左下角的值 已解答中等 相关标签相关企业 给定一个二叉树的 根节点 root,请找出该二叉树的 最底层最左边 节点的值。假设二叉树中至少有一个节点。 示例1:输入:root=[2,1,3]输出:1示例2:输入:[1,2,3,4,null,5,6,n......
  • 算法题记录
    试写一个python程序,求平面直角坐标系中两点的距离:classCoordinate:def__init__(self,x,y):self.x=xself.y=ydefdistance(self,other):x_diff_sq=(self.x-other.x)**2print(x_diff_sq)y_diff_sq=(self.y-other.y)**2......
  • 【算法】007_前缀树和贪心算法
    1.前缀树一个字符串类型的数组arr1,另一个字符串类型的数组arr2.arr2中有哪些字符,是arr1中出现的?arr2中有哪些字符是作为arr1中某个字符串前缀出现的?arr2中有哪些字符是作为arr1中某个字符串前缀出现的?pass:表示当前这个结点被经过的次数end:这个结点作为结尾的次数例如......