對於我來說,hash就像乙個加密軟體,你輸入乙個值,他就會輸出值,並且比之前的值更優,更方便。而這個值呢,就叫做雜湊值。然後字串雜湊就是輸入乙個字串,把它轉成對應的hash值就行了。
對於每個字串,我們通過乙個固定的轉換方式,使相同字串的雜湊值一定相同,不同字串的值盡量不同。因為很可能存在兩個不同的字串雜湊值一樣的操作,我們稱之為「雜湊衝突」。
我們此處傳換的方式,就是最常見的進製雜湊,它的核心是給出乙個固定進製base,把字串上面的每乙個元素看成base進製的每乙個數字,然後轉換成十進位制,最後的結果就是hash值。最後我們只需要比較每乙個字串的hash值就可以知道他們是不是同乙個字串。
關於進製的選擇,還是很自由的,但是一定不要含有mod的質因子(那你還模什麼模),所以我們取進製和mod時,一般都是質數。但是簡單的還是利用unsigned long long,不手動進行取模,它溢位時會自動對264
'>2^64取模
如題,給定n個字串(第i個字串長度為mi,字串內包含數字、大小寫字母,大小寫敏感),請求出n個字串中共有多少個不同的字串。
輸入格式:
第一行包含乙個整數n,為字串的個數。
接下來n行每行包含乙個字串,為所提供的字串。
輸出格式:
輸出包含一行,包含乙個整數,為不同的字串個數。
輸入樣例1
5abcaaaa
abcabcc
12345
輸出樣例1
4
對於這個雜湊,我們不對它取模,而是利用unsigned long long的溢位取模。
1 #include2#define fast std::ios::sync_with_stdio(false),std::cin.tie(0),std::cout.tie(0)
3using
namespace
std;
4 typedef unsigned long
long ull;//
typedef專門把c++的值的型別改名字,和巨集定義乙個道理,如自帶的int,char或者自定義的struct
5int n,ans=1;//
種類因為不搜第乙個,所以初值是一
6 ull base=131;//
進製數
7int a[10001];//
記錄hash值
8int hash(strings)9
15return sum;//
返回hash值 16}
17int
main()
1827 sort(a+1,a+1+n);//
hash值排序
28for(int i=2;i<=n;i++)
2932 cout<33 }
自定義取模的值就行了。
1 #include2#define fast std::ios::sync_with_stdio(false),std::cin.tie(0),std::cout.tie(0)
3using
namespace
std;
4int mod=20160817;//
神奇的數字(質數)但是交上去只能得80分,所以我們用乙個大一點的質數(212370440130137957ll) 不要在意後面的兩個符號,交上去就對了
5int n,ans=1;6
long
long
base=131;7
int a[100001];8
int hash(strings)9
16return sum;//
返回hash值 17}
18int
main()
1928 sort(a+1,a+1+n);//
hash值排序
29for(int i=2;i<=n;i++)
3033 cout<34 }
這其實就是你用不同的兩種或多種方式雜湊,然後分別比對每一種雜湊值是否相同——顯然是增加了空間和時間,但也確實增加了其正確性。
1 #include2#define fast std::ios::sync_with_stdio(false),std::cin.tie(0),std::cout.tie(0)
3using
namespace
std;
4int mod1=20160817;5
int mod2=19260817; 6
int n,ans=1;7
intbase=131;8
struct
nodea[100001
];11
int hash1(string
s)12
19return
sum;20}
21int hash2(string
s)22
29return sum;//
返回hash值 30}
31bool
sj(node x,node y)
3235
intmain()
3646 sort(a+1,a+1+n,sj);//
hash值排序
47for(int i=2;i<=n;i++)
4851 cout<52 }
說到底,我們雜湊還是來分辨字串的。有人說:字串不可以用map嗎?
可以的,但是你要知道,map是o(n)的,而雜湊只需要計算一下,就直接找到,o(1)的,所以明白了嗎?
這就是hash_map,也叫雜湊表
雜湊表呢,就是開一串陣列,然後每乙個字串對應乙個下標,而這個下標,就是他的雜湊值(因為這裡的陣列開不了很大,所以一般不用自然溢位)
所以就存在雜湊值重複的情況,我們這裡有三種操作方式
當雜湊值衝突的時候,我們就可以用鏈式前向星(就和那個存圖一樣的)
void add(intx)
這裡的key是雜湊值,last[i]是最後乙個雜湊值為i的編號,然後pre就是上乙個,連起來就行了。查詢的時候就像基本的前向星一樣查詢就是了,乙個乙個向上遍歷
這裡要提醒一下,當你的mod大,陣列就大,空間就大,相應的衝突就小,所以時間就比較快。而mod小了,陣列就小,空間小,相應的衝突大,所以時間就會慢,有的時候會超時。
這裡的線性勘測法就是有衝突的,下標就加一,如果還有,就繼續加一......
1void add(intx)2
找的時候一樣
bool find(intx)
所以這個時間複雜度還是很麻煩的,因為你會發現元素都是堆在一堆的,查詢很慢,所以我們要跳來跳去
這個用的就是平方跳跳跳,1^2,-1^2,2^2.......(s是平方陣列)
void add(intx) sum[key].x=x;
}
1bool find(intx)2
10if(!sum[key].x)return
false;11
return
true
;12 }
因為這種方法存在一直在跳迴圈,所以陣列空間最好開大點......
兩個輔助變數挖字串
1 有乙個字串符合以下特徵 abcdef,acccd,eeee,aaaa,e3eeeee,sssss,要求寫乙個函式 介面 輸出以下結果 1 以逗號分割字串,形成二維陣列,並把結果傳出 2 把二維陣列行數運算結果也傳出.2 請自己定義乙個介面 函式 要求1 能正確表達功能的要求,定義出介面 函式 3...
字串處理的兩個問題
處理字元是c語言中的常見操作,有兩個問題需要討論 一是判斷字元處理結束的標誌是空字元還是換行符,二是迴圈處理字元時,迴圈次數是字元陣列的容量大小還是實際輸入字元的個數。舉例 鍵盤輸入一行字元,統計大寫字元的個數。本例可用兩種方法程式設計,第一種方法的 如下 include int main 下面是第...
實現兩個長字串相加
兩個大數相加,且這兩個大數是正整數 暫時不考慮負數,不考慮輸入不合法的情況 要保證輸入是正確的才能保證程式正常執行 include include define maxsize 1000 int main temp1 j 0 j 0 for i len2 1 i 0 i 2.把兩個字串補齊,即短字串...