一、使用散列思想的查詢
1.給出N個整數,在給出M個數,問這M個數中的每個數是否在N個數中出現過
思路: 設定布爾型的數組
#include<stdio.h>
const int maxn = 100010;
bool hashArr[maxn] = {false};//用空間交換時間,而非對每個待查詢的數遍歷所有的數
//所謂hash是形成一個線性表,時間複雜度O(m+n)
int main(){
int n,m;
int x;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&x);
hashArr[x] = true;//標記是否存在
}
scanf("%d",&m);
int a;
for(int i=0;i<m;i++){
scanf("%d",&a);
if(hashArr[a]==true){
printf("yes\n");
}
else{
printf("no\n");
}
}
return 0;
}
2.進一步 我想知道每個數出現的次數
思路: int 型數組 對出現次數進行計數
#include<stdio.h>
const int maxn = 100010;
int hashTable[maxn] = {0};
int main(){
int n,m;
scanf("%d %d",&n,&m);
int x;
for(int i=0;i<n;i++){
scanf("%d",&x);
hashTable[x]++;//記錄出現次數
}
int a;
for(int i=0;i<m;i++){
scanf("%d",&a);
printf("%d\n",hashTable[a]);
}
return 0;
}
二、散列
上述思路中,我們直接把輸入的數作爲數組下標,來對這個數的性質進行統計。但是我們無法保證輸入的範圍,可能它超出我們的表示範圍,或者爲一個字符串。這時,我們提出散列,它本質是一種轉換過程,將元素通過一個函數轉換爲整數,使得該整數功能如數組下標,儘可能地唯一標識這個元素。
常用的散列函數:
線性變換,平方取中法,除留取餘法(較常用 H(key) = key % mod ,mod 一般取爲素數);
衝突: key1 不等於 key2 , H(key1) = H(key2)
解決衝突:線性探查法(hash值加一),平方探查,鏈地址法(將H(key)相同的key連接一條鏈表)
三、hash 初步
將字符串轉換爲唯一的整數
預備知識:A - Z 轉換爲0-25 (x-'A');字符轉換爲數字 (x-'0')
3.1 假設字符串中只含有大寫字母
int hashFunc(char a[],int len){//只含有大寫字母的情況
//字母A - Z 0-25 相當於26進制 ,把它轉換爲10進制
int sum = 0;
for(int i=0;i<len;i++){
sum = sum * 26 + (a[i] - 'A');
//a[i] - 'A' 0--25
}
return sum;
}
同時含有大小寫字母
int hashFunc2(char a[],int len){//含有大小寫字母,A-Z 0-25 a-z 26-51
//52進制轉換爲十進制
int id = 0;
for(int i=0;i<len;i++){
if(a[i]>='A' && a[i] <='Z'){
id = id * 52 + (a[i]-'A');
}
else if(a[i]>='a'&&a[i]<='z'){
id = id * 52 + (a[i]-'a'+ 26);
}
}
return id;
}
int hashTable(char a[],int len){
//形如BCD4 三位字符 加一個數字 -> 採用拼接
int id=0;
for(int i=0;i<len;i++){
id = id * 26 + (a[i]- 'A');
}
id = id*10 + (a[len-1]-'0');//注意字符形式轉換爲整數
retrun id;
}
給出N個字符串,查詢M的字符串(由三個大寫字母組成)在N個字符串中出現的次數
查詢時也要相應 轉化
#include<stdio.h>
#include<string.h>
const int maxn = 100;
char str[maxn][5];
char tmp[5];
int hashArr[26 * 26 * 26 + 10]={0};
int hashTable(char a[],int len){
int id =0;
for(int i=0;i<len;i++){
id = id * 26 + (a[i]-'A');
}
return id;
}
int main(){
int n,m;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%s",tmp);
int len1 = strlen(tmp);
int num = hashTable(tmp,len1);//
hashArr[num]++;
}
scanf("%d",&m);
for(int i=0;i<m;i++){
scanf("%s",tmp);
int len2 = strlen(tmp);
int num = hashTable(tmp,len2);//
printf("%d\n",hashArr[num]);
}
return 0;
}
2020/05/03
codeup題目整理 題意轉化
問題A:誰是你的潛在朋友 鏈接
共同朋友 轉換爲 ->即爲求每個書對應出現的次數
#include<stdio.h>
#include<string.h>
int cnt[210] = {0};//計數
int main(){
int n,m;
int a[210]={0};//書的映射
while(scanf("%d %d",&n,&m)!=EOF){
memset(cnt,0,sizeof(cnt));//無數遍了!!!計數器清零
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
cnt[a[i]]++;
}
for(int i=0;i<n;i++){
if(cnt[a[i]]>1){
printf("%d\n",cnt[a[i]]-1);
}
else{
printf("BeiJu\n");
}
}
}
return 0;
}
問題B:分組統計 較難
題目描述
先輸入一組數,然後輸入其分組,按照分組統計出現次數並輸出,參見樣例。
輸入
輸入第一行表示樣例數m,對於每個樣例,第一行爲數的個數n,接下來兩行分別有n個數,第一行有n個數,第二行的n個數分別對應上一行每個數的分組,n不超過100。
輸出
輸出m行,格式參見樣例,按從小到大排。
樣例輸入 Copy
1 7 3 2 3 8 8 2 3 1 2 3 2 1 3 1
樣例輸出 Copy
1={2=0,3=2,8=1} 2={2=1,3=0,8=1} 3={2=1,3=1,8=0}
1.使用二維數組建立關係,每個組 組中的元素散列計數
2.排序 併除去重複的元素
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn = 2010;
int cnt[maxn][maxn] = {0};
int x[110] = {0};
int g[110] = {0};
//由小到大排序 併合並重復元素
int del(int a[],int num){
sort(a,a+num);
int i,j;
for(i=0,j=1;j<num;j++){
if(a[i]!=a[j]){//後面的不重複則繼續推進
a[++i] = a[j]; //a[1]
}
}
return i+1;
}
int main(){
int n;
while(scanf("%d",&n)!=EOF){
int num = 0;
for(int i=0;i<n;i++){
memset(cnt,0,sizeof(cnt));
scanf("%d",&num);
for(int j=0;j<num;j++){
scanf("%d",&x[j]);
}
for(int j=0;j<num;j++){//組和元素如何對應並完成分組的計數
scanf("%d",&g[j]);
cnt[g[j]][x[j]]++;//使用二維數組建立關係,對應關係下每個組中元素的計數
}
int g0 = del(g,num);
int x0 = del(x,num);
for(int i=0;i<g0;i++){
printf("%d",g[i]);
printf("={");
for(int j=0;j<x0;j++){
printf("%d=%d",x[j],cnt[g[i]][x[j]]);
if(j<x0-1) printf(",");
}
printf("}\n");
}
}
}
return 0;
}
問題 C: Be Unique (20) 題目
所謂unique 就是出現次數爲一即可,不用想着去把相同的元素刪除掉,而是 唯一出現的元素最終輸出出來
#include<stdio.h>
#include<string.h>
const int maxn = 100000;
int ex[maxn]={0};
int a[maxn] = {0};
int main(){
int n;
while(scanf("%d",&n)!=EOF){
memset(ex,0,sizeof(ex));
int x;
for(int i=0;i<n;i++){
scanf("%d",&x);
a[i] = x;
ex[a[i]]++;
}
int flag = 0;
for(int i=0;i<n;i++){
if(ex[a[i]] == 1){//唯一 次數爲1
flag = 1;
printf("%d\n",a[i]);
break;
}
}
if(flag==0){
printf("None\n");
}
}
return 0;
}
問題 D: String Subtraction (20) 題目
將大字符串a 中,出現在小字符串b中的字符去掉 使用hash 思路標記某個字母是否存在即可
#include<stdio.h>
#include<string.h>
char a[10010];
char b[10010];
int main(){
gets(a);
gets(b);
bool b0[300] = {false};
for(int i=0;i<strlen(b);i++){
b0[b[i]] = true;//在或不在
}
for(int j=0;j<strlen(a);j++){
if(b0[a[j]]==false){
printf("%c",a[j]);
}
}
printf("\n");
return 0;
}