重新认识Hash表
1. 模拟哈希表
1.1 开放寻址法
开放寻址法- 线性探测法
#include<iostream>
#include<cstring>
using namespace std;
const int N = 2e5+10,null = 0x3f3f3f3f;
int p[N];
int find(int x){
int index = (x%N+N)%N;
while(p[index] != null&& p[index] != x){
index = (index+1)%N;
}
return index;
}
int main(){
int n;
scanf("%d",&n);
//int有四个字节,按字节初始化
memset(p,0x3f,sizeof p);
while(n--){
char a[2];
int b;
scanf("%s%d",a,&b);
if(*a =='I'){
p[find(b)] = b;
}else{
if(p[find(b)] == null){
puts("No");
}else{
puts("Yes");
}
}
}
}
1.2 拉链法
#include<iostream>
#include<cstring>
using namespace std;
const int N = 200003;
int a[N],e[N],ne[N],h[N],idx,n;
void insert(int b){
int a = (b%N+N)%N;
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
bool find(int x){
int u = (x%N+N)%N;
for(int i = h[u]; i != -1; i = ne[i]){
if(e[i] == x){
return true;
}
}
return false;
}
int main(){
// char *类型 。它是一个指针,这个指针指向一个字符串。
// char [] 类型。它是一个数组,他代表了这堆内存空间。
memset(h,-1, sizeof h);
scanf("%d",&n);
while(n--){
char x[2];
int y;
scanf("%s%d",x,&y);
if(*x == 'I'){
insert(y);
}else{
if(find(y)){
puts("Yes");
}else{
puts("No");
}
}
}
}
2. 字符串哈希
字符串前缀哈希法
设 str = “abcacbabc”
设h[0] = 0
h[1] 是a的hash值
h[2]是ab的hash值
那么如何对字符的hash值进行保存,可以利用p进制就是利用ASCII值进行计算
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int N = 100010, P = 131;
int n,m;
char str[N];
ULL h[N],p[N];
ULL get(int l,int r){
return h[r] - h[l-1]*p[r-l+1];
}
int main(){
scanf("%d%d",&n,&m);
scanf("%s",str+1);
p[0] = 1;
for(int i = 1; i <= n; i++){
//计算并预处理进制
p[i] = p[i-1]*P;
//计算每一个前缀和的哈希值
h[i] = h[i-1]*P+str[i];
}
while(m--){
int l1,r1,l2,r2;
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
if(get(l1,r1) == get(l2,r2)){
puts("Yes");
}else{
puts("No");
}
}
return 0;
}
2.1 处理字符串经常用的还有KMP
#include<iostream>
#include<cstring>
const int N = 1e5+10, M = 1e6+10;
char p[N],s[M];
int ne[N];
int n,m;
int main(){
scanf("%d%s",&n,p+1);
scanf("%d%s",&m,s+1);
//计算next数组
for(int i = 2, j = 0; i <= n; i++){
while(j && p[i] != p[j+1]){
j = ne[j];
}
if(p[i] == p[j+1]){
j++;
}
ne[i] = j;
}
for(int i = 1, j = 0; i <= m; i++){
while(j && s[i] != p[j+1]){
j = ne[j];
}
if(s[i] == p[j+1]){
j++;
}
if(j==n){
printf("%d ",i-n);
}
}
return 0;
}
作者:acw_zzd
链接:https://www.acwing.com/activity/content/code/content/1600923/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
3. leetcode 习题 187
class Solution {
public:
vector<string> findRepeatedDnaSequences(string s) {
unordered_map<string,int> hash;
vector<string> ans;
for(int i = 0; i+10 <= s.length(); i++){
hash[s.substr(i,10)]++;
}
for(auto &[k,v]:hash){
if(v > 1){
ans.push_back(k);
}
}
return ans;
}
};
class Solution {
int N = (int)1e5+10, P = 13331;
int[] h = new int[N], p = new int[N];
public List<String> findRepeatedDnaSequences(String s) {
int n = s.length();
List<String> ans = new ArrayList<>();
p[0] = 1;
for (int i = 1; i <= n; i++) {
h[i] = h[i - 1] * P + s.charAt(i - 1);
p[i] = p[i - 1] * P;
}
Map<Integer, Integer> map = new HashMap<>();
for (int i = 1; i + 10 - 1 <= n; i++) {
int j = i + 10 - 1;
int hash = h[j] - h[i - 1] * p[j - i + 1];
int cnt = map.getOrDefault(hash, 0);
if (cnt == 1) ans.add(s.substring(i - 1, i + 10 - 1));
map.put(hash, cnt + 1);
}
return ans;
}
}
字符串哈希加二分解决最长回文子串(好题)
解析描述
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int N = 2e6+10,P = 131;
ULL sl[N],sr[N],p[N];
char ss[N];
ULL get(ULL s[],int l,int r){
return s[r] - s[l-1] * p[r-l+1];
}
int main(){
int T = 1;
while(scanf("%s",ss+1),strcmp(ss+1,"END")){
int n = strlen(ss+1);
//初始化字符串
for(int i = n*2; i ; i-=2){
ss[i] = ss[i/2];
ss[i-1] = 'z'+1;
}
n*=2;
p[0] = 1;
for(int i = 1, j = n; i <= n; i++,j--){
p[i] = p[i-1] *P;
sl[i] = P * sl[i-1]+ss[i];
sr[i] = P * sr[i-1]+ss[j];
}
int res = 0;
for(int i = 1; i <= n; i++){
//半径的最大长度
int l = 0, r = min(i-1,n-i);
while(l < r){
int mid = (l+r+1)>>1;
if(get(sl,i-mid,i-1) == get(sr,n-(i+mid)+1,n-(i+1)+1)){
l = mid;
}else{
r = mid - 1;
}
}
if(ss[i-l] <='z'){
res = max(res,l+1);
}else{
res = max(res,l);
}
}
printf("Case %d: %d\n",T++,res);
}
}