哈希

哈希

常用于需要 \(O(1)\) 比较两个 \(O(n)\) 的东西。可以采用双模数减少冲突概率。

哈希冲突率的粗略计算:可以看做 \(\frac{n}{\prod mod}\)

字符串哈希

常用于需要 \(O(1)\) 比较两个字符串,可以代替一些字符串匹配的 KMP 题目。以及可以使用哈希 + 二分的技巧 \(\log\) 的时间比较两个字符串的大小。

一般求出每个前缀的哈希值,然后子串哈希值就可以通过差分得到。

比较字符串大小的技巧是,二分第一个出现不同的位置,每次比较使用哈希判断,因此时间复杂度是 \(O(\log len)\) 的。

哈希表

如果不卡 \(\log\) 和常数的话可以使用 map,如果 key 值是标准类型可以使用 unordered_map,如果不是标准类型需要手写哈希函数比较麻烦,而且 STL 常数太大,不如自己手写哈希表。

哈希表的工作原理是对于一个 val 值计算哈希函数,存在桶里,如果不同 val 值的哈希值冲突,则以某种方式换一个地方存储。可以有效处理哈希冲突。

不过由于哈希函数的计算时间取决于 val 的长度,所以如果你需要映射一个数组等很长的东西,可能需要先使用双哈希算出数组的哈希,再把双哈希插入哈希表。

因为出题人不一定可以卡到你的模数,所以哈希表的操作可以看做 \(O(1)\) 的。

哈希表常用模数有 \(1e7+103\)

拉链法

对于每一个 key 开一个链式前向星结构来处理冲突。比较好理解而且不难写。

板子代码。

const int sz=1e7+103;
struct _hash{
	int head[sz];
	int f(pii key) {
		return (key.fi+key.se)%sz;
	}
	struct _map {
		pii val;
		int key;
		int num;
		int ne;
	}mp[N];
	int cnt;
	void clear() {
		while(cnt) head[mp[cnt--].key]=0;
	}
	int find(pii key) {
		int h=f(key);
		for(int i=head[h];i;i=mp[i].ne) if(mp[i].val==key) return i;
		return 0; 
	}
	void insert(pii key) {
		int h=f(key);
		int it=find(key);
		if(it) mp[it].num++;
		else mp[++cnt]={key,h,1,head[h]},head[h]=cnt;
	}
	int operator [] (int it) const { return mp[it].num; }
}hashmp;

经验

20AB-day3 Good Subsegments

posted @ 2024-10-12 08:18  wing_heart  阅读(18)  评论(0)    收藏  举报