散列(hash)练习题
目錄
- 誰是你的潛在朋友 【★】
- 是唯一的 【★】
- 字符串減法 【★★】
- 分組統計【★★★】
在哈希這一塊常用的問題包括:判斷<=105個正整數中某m個正整數是否出現過、出現了多少次——聲明bool/int hashTable[maxn] = {false}/{0}。其做法本質是直接將輸入的整數作為數組的下標來對這個數的性質進行統計,即hash(key)=key直接定址,是最常見也最實用的散列應用。復雜一點還有二次映射。把這兩個思想掌握了就差不多了。
本篇文章有的內容來自 https://blog.csdn.net/myRealization/article/details/80154726
誰是你的潛在朋友 【★】
http://codeup.cn/problem.php?cid=100000582&pid=0
-
題目描述
“臭味相投”——這是我們描述朋友時喜歡用的詞匯。兩個人是朋友通常意味著他們存在著許多共同的興趣。然而作為一個宅男,你發現自己與他人相互了解的機會 并不太多。幸運的是,你意外得到了一份北大圖書館的圖書借閱記錄,于是你挑燈熬夜地編程,想從中發現潛在的朋友。
首先你對借閱記錄進行了一番整理,把N個讀者依次編號為1,2,…,N,把M本書依次編號為1,2,…,M。同時,按照“臭味相投”的原則,和你喜歡讀同一本書的人,就是你的潛在朋友。你現在的任務是從這份借閱記錄中計算出每個人有幾個潛在朋友。 -
輸入
每個案例第一行兩個整數N,M,2 <= N ,M<= 200。接下來有N行,第i(i = 1,2,…,N)行每一行有一個數,表示讀者i-1最喜歡的圖書的編號P(1<=P<=M) -
輸出
每個案例包括N行,每行一個數,第i行的數表示讀者i有幾個潛在朋友。如果i和任何人都沒有共同喜歡的書,則輸出“BeiJu”(即悲劇,^ ^)
用數組做下標,直接定址hash
#include<cstdio> int main(void) {int M,N;int i;while(scanf("%d%d",&N,&M)!=EOF){int a[M+1]={0};int student[N+1]={0};for(i=1;i<=N;i++){scanf("%d",&student[i]);a[student[i]]++;}for(i=1;i<=N;i++){if( (a[student[i]]-1) == 0 ){printf("BeiJu\n");continue;}printf("%d\n",a[student[i]]-1);}}return 0; }是唯一的 【★】
- 題目描述
對火星上的人們來說,獨特是如此重要,以至于他們的彩票也是以一種獨特的方式設計的。獲勝的規則很簡單:一次下注是從[1,104]中選擇一個數字。第一個押注于唯一號碼的人獲勝。例如,如果有7人在5 31 5 88 67 88 88 17上下注,那么第二個押注31的人就贏了。 - 輸入
每個輸入文件包含一個測試用例。每一種情況都包含以正整數N開頭的一行(N<=105),然后是N次下注。數字用空格分隔。 - 輸出
對于每個測試用例,用一行打印獲勝號碼。如果沒有贏家,則打印“無”。
用數組做下標,直接定址hash
#include<cstdio> int a[10005]; int main(void) {int N;int i;int flag;while(scanf("%d",&N)!=EOF){flag=0;int student[N+1]={0};for(i=1;i<=N;i++){scanf("%d",&student[i]);a[student[i]]++;}for(i=1;i<=N;i++){if( a[student[i]] == 1 ){printf("%d\n",student[i]);flag=1;break;}}if(!flag){printf("None\n");}}return 0; }字符串減法 【★★】
- 題目描述
給定兩個字符串S1和S2,S=S1-S2定義為S中所有字符之后的剩余字符串。2來自S1。你的任務只是計算S1-S2對于任何給定的字符串。然而,做這件事可能并不那么簡單。快地. - 輸入
每個輸入文件包含一個測試用例。每個案例包含兩行,給出S1和S2分別。這兩個字符串的字符串長度不超過10。4。保證所有字符都是可見的ASCII代碼和空格,一個新的行字符表示字符串的結束。 - 輸出
對于每個測試用例,打印S1-S2一條線。
用數組做下標,直接定址hash
#include<cstdio> #include<cstring> char s1[1005],s2[1005]; bool hush[130]={false}; int main(void) {int i=0;while( gets(s1) != NULL){gets(s2);for(i=0;i<strlen(s2);i++){hush[s2[i]]=true;//確定重復}for(i=0;i<strlen(s1);i++){if(hush[s1[i]]==false)printf("%c",s1[i]);}}return 0; }分組統計【★★★】
-
題目描述
先輸入一組數,然后輸入其分組,按照分組統計出現次數并輸出,參見樣例。 -
輸入
輸入第一行表示樣例數m,對于每個樣例,第一行為數的個數n,接下來兩行分別有n個數,第一行有n個數,第二行的n個數分別對應上一行每個數的分組,n不超過100。 -
輸出
輸出m行,格式參見樣例,按從小到大排。
解析:這一道題目可以說是集整數哈希思想于大成,值得仔細分析。
- 首先,題目中說輸入的數據量不超過100,類別同樣不超過100,但是沒有說數據的具體范圍,可能會在整數作為數組的下標超過數組下標范圍,理論上來說,對于這種題目,以空間換時間,要求數據應該不超過106。因此,統計輸入的數據和組別是否已經出現,可以開hashTable[100100]這樣大。
- 去重操作。在有了標識數據是否出現的哈希表的情況下,可以很簡單的做到。
答案矩陣是一個二次映射的二維數組,可以直接通過組別和數據查到相應組別的數據出現的次數。
出現50%錯誤:如果二維數組開的太小,很容易溢出,所以記錄第一行數據中最大的值,將其+10作為二維數組中的列數即可解決。
思路:
用數組做下標,直接定址hash,和二次映射的hash
#include <cstdio> #include <algorithm> using namespace std;int main() {int m;scanf("%d", &m);while (m--) {int n, maxCol = 0, data[110], group[110]; //分別記錄輸入的數據和分組scanf("%d", &n);//nums記錄輸入的數據去重后的數據 int nums[120], len1 = 0;//使用哈希表對data進行存在標識, 以便去重 bool hashTable1[100100] = {false}; for (int i = 0; i < n; i++) { scanf("%d", &data[i]); //邊錄入邊去重 if (!hashTable1[data[i]]) { //如果這個數據尚未被記錄 nums[len1++] = data[i]; hashTable1[data[i]] = true; }//得到最大的數, 方便答案直接映射而不溢出 if (maxCol < data[i]) maxCol = data[i]; } sort(nums, nums + len1); //數據從小到大存放在nums中, 無重復 //g記錄輸入的組別去重后的數據 int g[120], len2 = 0; //使用哈希表對group進行存在標識, 以便去重bool hashTable2[100100] = {false};/*二維答案表,元素ans[g[i]][nums[j]]表示g[i]組中對應的nums[j]出現的次數 ans[i][j], i為分組, j為數, a[i][j]為第i組的j數出現的次數 */int ans[n + 10][maxCol + 10] = {0}; for (int i = 0; i < n; i++) {scanf("%d", &group[i]);ans[group[i]][data[i]]++; if (!hashTable2[group[i]]) { //如果這個組別尚未被記錄 g[len2++] = group[i]; hashTable2[group[i]] = true;} }sort(g, g + len2); //組別從小到大存放在g中, 無重復 //輸出結果 for (int i = 0; i < len2; i++) {printf("%d={", g[i]);for (int j = 0; j < len1; j++) {printf("%d=%d", nums[j], ans[g[i]][nums[j]]);if (j < len1 - 1) printf(",");else printf("}\n");}} }return 0; } 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的散列(hash)练习题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 散列(哈希 hash)
- 下一篇: sort函数的应用习题(二)