哈希表 通俗理解

哈希表

在這里插入圖片描述

1. 模擬散列表

把一大堆整數(shù)串纺,范圍很大零散的,映射為在某一范圍的

例題:840. 模擬散列表

維護(hù)一個(gè)集合搓萧,支持如下幾種操作:

  1. “I x”,插入一個(gè)數(shù)x;
  2. “Q x”压彭,詢問數(shù)x是否在集合中出現(xiàn)過闻妓;

現(xiàn)在要進(jìn)行N次操作菌羽,對(duì)于每個(gè)詢問操作輸出對(duì)應(yīng)的結(jié)果。

輸入格式

第一行包含整數(shù)N由缆,表示操作數(shù)量注祖。

接下來N行,每行包含一個(gè)操作指令均唉,操作指令為”I x”是晨,”Q x”中的一種。

輸出格式

對(duì)于每個(gè)詢問指令“Q x”舔箭,輸出一個(gè)詢問結(jié)果罩缴,如果x在集合中出現(xiàn)過蚊逢,則輸出“Yes”,否則輸出“No”箫章。

每個(gè)結(jié)果占一行烙荷。

數(shù)據(jù)范圍

1≤N≤10^5

?109≤*x*≤109

輸入樣例:

5
I 1
I 2
I 3
Q 2
Q 5

輸出樣例:

Yes
No

1.1 拉鏈法散列表

思路:和圖的臨界表存儲(chǔ)類似,詳見之前寫的文章:樹和圖的深度優(yōu)先搜索(應(yīng)用:樹的重心)

用一維數(shù)組存儲(chǔ)哈希值檬寂,對(duì)于大范圍的數(shù)终抽,每次模上一個(gè)數(shù)p,然后映射到數(shù)組下標(biāo),一般p取大于n的第一個(gè)質(zhì)數(shù),這樣沖突最小

x ==> h[x % p] ,h存放的是每個(gè)拉鏈的指針

在這里插入圖片描述

平均下桶至,每條鏈表很短昼伴,一般是O(1)算法

模板

int h[N], e[N], ne[N], idx;
// 向哈希表中插入一個(gè)數(shù)
void insert(int x)
{
    int k = (x % N + N) % N;
    e[idx] = x;
    ne[idx] = h[k];
    h[k] = idx ++ ;
}

// 在哈希表中查詢某個(gè)數(shù)是否存在
bool find(int x)
{
    int k = (x % N + N) % N;
    for (int i = h[k]; i != -1; i = ne[i])
        if (e[i] == x)
            return true;

    return false;
}
  1. 模擬散列表
#include <iostream>
#include <cstring>

using namespace std;

int n,x;
const int N = 100003;
int h[N],e[N],ne[N],idx;

void insert(int x);
bool find(int x);

int main(){
    
    cin>>n;
    memset(h,-1,sizeof h);

    while(n--){
        char op[2];
        scanf("%s%d",op,&x);
        if(*op == 'I')
            insert(x);
        else{
            if(find(x))
                printf("Yes\n");
            else
                printf("No\n");
            
        }
            
            
    }
    return 0;
}

void insert(int x){
    
    int k = (x % N + N) % N;
    e[idx] = x;
    ne[idx] = h[k];
    h[k] = idx++;
    
}

bool find(int x){
    int k = (x % N + N) % N;
    for(int i = h[k];i != -1;i = ne[i])
        if(e[i] == x)
            return true;
    return false;
}

1.2 開放尋址法

思路:只開一維數(shù)組(一般數(shù)組大小為第一個(gè)大于2n 的素?cái)?shù)*),插入時(shí)有空位就插镣屹,沒空位就找下一個(gè)空位圃郊,一直到找到為止,查詢也是如果當(dāng)前位置空了就沒有該元素女蜈,否則就判斷該元素是不是持舆,不是就接著往前循環(huán)找,知道找到第一個(gè)空位結(jié)束(注意鞭光,由于數(shù)組夠大吏廉,所以一定有空位)

#include <iostream>
#include <cstring>

using namespace std;

int n,x;
const int N = 200003;
const int null = 0x3f3f3f3f;
int h[N];

int find(int x);

int main(){
    
    cin>>n;
    memset(h,0x3f,sizeof h);

    while(n--){
        char op[2];
        scanf("%s%d",op,&x);
        int t = find(x);
        if(*op == 'I'){
            h[t] = x;
        }
        else{
            if(h[t] != null)
                printf("Yes\n");
            else
                printf("No\n");
            
        }
            
            
    }
    return 0;
}


//如果有這個(gè)數(shù)就返回這個(gè)數(shù)的下標(biāo),沒有就返回下一個(gè)空位
int find(int x){
    int k = (x % N + N) % N;
    while(h[k] != null && h[k] != x){
        k++;
        if(k == N)
            k = 0;
    }

    return k;
}


總結(jié):剛看了下惰许,兩算法的時(shí)間復(fù)雜度一樣的席覆,都是O(n)的,不過我更喜歡第一個(gè)拉鏈法汹买。然后剛測(cè)了下unordered_set和unordered_map,發(fā)現(xiàn)還是上面兩個(gè)快

03.jpg

2. 字符串哈希

例題:841. 字符串哈希

給定一個(gè)長(zhǎng)度為n的字符串佩伤,再給定m個(gè)詢問,每個(gè)詢問包含四個(gè)整數(shù) l1,r1,l2,r2晦毙,請(qǐng)你判斷[l1,r1]和[l2,r2]這兩個(gè)區(qū)間所包含的字符串子串是否完全相同生巡。
字符串中只包含大小寫英文字母和數(shù)字。

輸入格式

第一行包含整數(shù)n和m见妒,表示字符串長(zhǎng)度和詢問次數(shù)孤荣。

第二行包含一個(gè)長(zhǎng)度為n的字符串,字符串中只包含大小寫英文字母和數(shù)字须揣。

接下來m行盐股,每行包含四個(gè)整數(shù)l1,r1,l2,r2,表示一次詢問所涉及的兩個(gè)區(qū)間耻卡。

注意疯汁,字符串的位置從1開始編號(hào)。

輸出格式

對(duì)于每個(gè)詢問輸出一個(gè)結(jié)果卵酪,如果兩個(gè)字符串子串完全相同則輸出“Yes”幌蚊,否則輸出“No”谤碳。每個(gè)結(jié)果占一行。

數(shù)據(jù)范圍

1≤n,m≤10^5

輸入樣例:

8 3
aabbaabb
1 3 5 7
1 3 6 8
1 2 1 2

輸出樣例:

Yes
No
Yes

核心思想:將字符串看成P進(jìn)制數(shù)溢豆,P的經(jīng)驗(yàn)值是131或13331蜒简,取這兩個(gè)值的沖突概率低
小技巧:取模的數(shù)用2^64,這樣直接用unsigned long long存儲(chǔ)沫换,溢出的結(jié)果就是取模的結(jié)果

具體點(diǎn)臭蚁,就是把一個(gè)字符串如”ABC”映射成一個(gè)p進(jìn)制的數(shù)字
“ABC” –> p^2+A + p^1+B + p^0+C = 哈希值最铁, 一般p取131或13331

"ABCDEFGHI"
 123456789   (下標(biāo))
     L   R

字符串"A"的    哈希值為 p^0+A
字符串"AB"     哈希值為 p^1+A + p^0+B
字符串"ABC"    哈希值為 p^2+A + p^1+B + C
字符串[1,L-1]的哈希值為 p^3+A + p^2+B + p^1+C + p^0+D
字符串[1,R]  的哈希值為 p^8+A + p^7+B +  ...  + P^0+I     

h[r] - h[l - 1] * p[r - l + 1]

注:此處看的別人的題解才看懂的:https://www.acwing.com/solution/content/3613/

代碼:

#include <iostream>
#include <algorithm>

using namespace std;

typedef unsigned long long ULL;

const int N = 100010, P = 131;

int n, m;
char str[N];
ULL h[N], p[N];

ULL get(int l, int r)
{
    return h[r] - h[l - 1] * p[r - l + 1];
}

int main()
{
    scanf("%d%d", &n, &m);
    scanf("%s", str + 1);

    p[0] = 1;
    for (int i = 1; i <= n; i ++ )
    {
        h[i] = h[i - 1] * P + str[i];
        p[i] = p[i - 1] * P;
    }

    while (m -- )
    {
        int l1, r1, l2, r2;
        scanf("%d%d%d%d", &l1, &r1, &l2, &r2);

        if (get(l1, r1) == get(l2, r2)) puts("Yes");
        else puts("No");
    }

    return 0;
}

總結(jié):今天用stl中的string中的sunstr()方法試了試讯赏,發(fā)現(xiàn)效率確實(shí)沒這個(gè)快

04.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市冷尉,隨后出現(xiàn)的幾起案子漱挎,更是在濱河造成了極大的恐慌,老刑警劉巖雀哨,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件磕谅,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡雾棺,警方通過查閱死者的電腦和手機(jī)膊夹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來捌浩,“玉大人放刨,你說我怎么就攤上這事∈龋” “怎么了进统?”我有些...
    開封第一講書人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)浪听。 經(jīng)常有香客問我螟碎,道長(zhǎng),這世上最難降的妖魔是什么迹栓? 我笑而不...
    開封第一講書人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任掉分,我火速辦了婚禮,結(jié)果婚禮上克伊,老公的妹妹穿的比我還像新娘酥郭。我一直安慰自己,他們只是感情好答毫,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開白布褥民。 她就那樣靜靜地躺著,像睡著了一般洗搂。 火紅的嫁衣襯著肌膚如雪消返。 梳的紋絲不亂的頭發(fā)上载弄,一...
    開封第一講書人閱讀 49,929評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音撵颊,去河邊找鬼宇攻。 笑死,一個(gè)胖子當(dāng)著我的面吹牛倡勇,可吹牛的內(nèi)容都是我干的逞刷。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼妻熊,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼夸浅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起扔役,我...
    開封第一講書人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤帆喇,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后亿胸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坯钦,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年侈玄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了婉刀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡序仙,死狀恐怖突颊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情诱桂,我是刑警寧澤洋丐,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站挥等,受9級(jí)特大地震影響友绝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜肝劲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一迁客、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧辞槐,春花似錦掷漱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鹿榜,卻和暖如春海雪,著一層夾襖步出監(jiān)牢的瞬間锦爵,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來泰國打工奥裸, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留险掀,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓湾宙,卻偏偏與公主長(zhǎng)得像樟氢,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子侠鳄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容