算法筆記算法初步(4.2散列)

一、使用散列思想的查詢

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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章