原題連結:https://www.luogu.com.cn/problem/P3370
題意解讀:本題要求理解雜湊的原理,自行建立雜湊表解題,如果直接使用map,就不推薦。
解題思路:
先介紹雜湊的原理
1、什麼是雜湊?什麼是雜湊表?
先從一個問題出發:給定不超過105個整數(取值1~109),要統計不重複整數的數量。
首先,如果取值範圍是1~105,可以藉助計數排序的思想,定義陣列int a[N],N在1e5規模,遍歷所有整數,對出現的整數標記a[i] = 1,最後統計>0的個數;
但是,由於取值範圍是1~109,如果定義陣列int a[N],N在1e9規模,記憶體會爆掉,能不能用更小的資料結構來搞定呢?
可以定義vector<int> a[M],M在1e5規模內即可
對於每一個整數i,先計算i % M,取模之後必然落到[0~M)區間,然後將i存入a[i % M].push_back(i)
在存入i之前,可以判斷a[i % M]這個vector裡是否已經存在了i,存在則不加入
最後,遍歷所有a[k],累加a[k].size()即得不重複的整數數量。
把一個大的整數對映到一個小整數的過程叫做雜湊,如i % M;
而用來儲存元素的vector<int> a[M]則稱為雜湊表。
2、字串如何雜湊?
字串也可以轉化為整數,只需把字串當做p進位制數來處理即可
例如:ABC,轉成數字:'A' * p2 + 'B' * p1 + 'C' * p0
再對一個合適的M取模:('A' * p2 + 'B' * p1 + 'C' * p0) % M
就完成了字串的雜湊
通常:P取一個素數會減少衝突,常見選擇如:131、13331
M則根據實際資料量進行選擇即可。
100分程式碼:
#include <bits/stdc++.h>
using namespace std;
const int N = 10005, M = 10000, P = 131;
vector<string> h[N];
int n, ans;
string s;
int main()
{
cin >> n;
while(n--)
{
cin >> s;
int hashcode = 0;
for(int i = 0; i < s.size(); i++)
{
hashcode = (hashcode * P + s[i]) % M; //類似二進位制轉十進位制的操作計算hashcode,每次都要%M以免溢位
}
bool exist = false; //s是否已經存在
for(int i = 0; i < h[hashcode].size(); i++) //在h[hashcode]中查詢s是否存在
{
if(h[hashcode][i] == s)
{
exist = true;
break;
}
}
if(!exist)
{
h[hashcode].push_back(s); //如果s不存在則新增
ans++;
}
}
cout << ans;
return 0;
}