複習(二):KMP、Trie、最大異或對、

Yuan Yulin發表於2020-11-01

————————————————————2020年10月25日(週日)

一、KMP

第四次了,發現還是記不住……因為之前沒好好做筆記……
答案&註釋

#include <iostream>

using namespace std;

const int N = 100010, M = 1000010;

int n, m;
int ne[N];
char s[M], p[N];

int main()
{
    cin >> n >> p + 1 >> m >> s + 1;
    
//首先是處理好ne陣列,作用是當匹配不成功時,嘗試從上一個出現當前字元的地方開始找,不至於從頭再來。 
    for (int i = 2, j = 0; i <= n; i ++ )
    {
    //這裡就是一點一點地往回退,從頭開始太傻了。
        while (j && p[i] != p[j + 1]) j = ne[j];
        //找到可以往後一步的地方就j加1
        if (p[i] == p[j + 1]) j ++ ;
        //然後將對應i位置的ne設為j
        ne[i] = j;
    }
    
//開始尋找,其實兩者程式碼是差不多的,因為找的時候也是一步一步往回退著找的。
    for (int i = 1, j = 0; i <= m; i ++ )
    {
        while (j && s[i] != p[j + 1]) j = ne[j];
        if (s[i] == p[j + 1]) j ++ ;
        if (j == n)
        {
            printf("%d ", i - n);
            j = ne[j];
        }
    }

    return 0;
}

二、Trie


理解之後覺得挺簡單的,就這樣吧。
連註釋都不注的答案

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;

int son[N][26], cnt[N], idx;
char str[N];

void insert(char *str){
    int p = 0;
    for(int i = 0; str[i]; i ++){
        int u = str[i] - 'a';
        if(!son[p][u]) son[p][u] = ++idx;
        p = son[p][u];
    }
    cnt[p] ++;
}

int  query(char *str){
    int p = 0;
    for(int i = 0 ; str[i]; i ++){
        int u = str[i] - 'a';
        if(!son[p][u]) return 0;
        p = son[p][u];
    }
    return cnt[p];
}

int main(){
    int n;
    scanf("%d", &n);
    while(n --){
        char op[2];
        scanf("%s%s", op, str);
        if(*op == 'I') insert(str);
        else printf ("%d\n", query(str));
        
        
    }
    return 0;
}

三、最大異或對

傳送
一週前剛刷完……
(然而過了一週後再看,發現又忘記怎麼做了……我的記憶果然是假的。

不過這次刷完Trie之後再看,發現其實做法和Trie真的很像,就是Trie的一種運用。

(注:-1的二進位制碼全是 1,所以 ~-1 == 0 !

註釋版 & 思路

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010, M = 3000000;
int n;
int a[N], son[M][2], idx;

void insert(int x)
{
    int p = 0;
    for (int i = 30; i >= 0; i -- )
    {
        int &s = son[p][x >> i & 1];
        if (!s) s = ++ idx;
        p = s;
    }
}//這個函式就是說,將這個數分解為一個二進位制數,然後按照這個二進位制不斷地往下開闢一條道路
//每到一個新節點就給它取一個新的名字,這樣往下找兒子的時候就不會產生混亂……

int search(int x)
{
    int p = 0, res = 0;
    for (int i = 30; i >= 0; i -- )
    {
        int s = x >> i & 1;
        if (son[p][!s])
        {
            res += 1 << i;
            p = son[p][!s];
        }
        else p = son[p][s];
    }
    return res;
}

int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n; i ++ )
    {
        scanf("%d", &a[i]);
        insert(a[i]);
    }

    int res = 0;
    for (int i = 0; i < n; i ++ ) res = max(res, search(a[i]));

    printf("%d\n", res);

    return 0;
}

To be continue……

相關文章