1. 程式人生 > 其它 >KMP,trie樹,並查集

KMP,trie樹,並查集

KMP

記憶化搜尋,ne用來記錄最大前後綴

// s[]是長文字,p[]是模式串,n是s的長度,m是p的長度

#include <iostream>
using namespace std;
const int N = 1e5 + 10;
char s[N], p[N];
int ne[N];
int n, m;

int main() {
	cin >> m >> p + 1 >> n >> s + 1;
	//求模式串的Next陣列:
	for (int i = 2, j = 0; i <= m; i ++ ) {
		while (j && p[i] != p[j + 1])
			j = ne[j];
		if (p[i] == p[j + 1])
			j ++;
		ne[i] = j;
	}
// 匹配
	for (int i = 1, j = 0; i <= n; i ++ ) {
		while (j && s[i] != p[j + 1])
			j = ne[j];
		if (s[i] == p[j + 1])
			j ++;
		if (j == m) {
			cout << i - m << ' ';// 匹配成功後的邏輯
			j = ne[j];
		}
	}
	return 0;
}

trie樹

int son[N][26], cnt[N], idx;//idx是結點下標
// 0號點既是根節點,又是空節點
// son[][]儲存樹中每個節點的子節點
// cnt[]儲存以每個節點結尾的單詞數量

// 插入一個字串
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];
}

並查集

(1)樸素並查集:

    int p[N]; //儲存每個點的祖宗節點

    // 返回x的祖宗節點
    int find(int x)
    {
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }

    // 初始化,假定節點編號是1~n
    for (int i = 1; i <= n; i ++ ) p[i] = i;

    // 合併a和b所在的兩個集合:
    p[find(a)] = find(b);


(2)維護size的並查集:

    int p[N], size[N];
    //p[]儲存每個點的祖宗節點, size[]只有祖宗節點的有意義,表示祖宗節點所在集合中的點的數量

    // 返回x的祖宗節點
    int find(int x)
    {
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }

    // 初始化,假定節點編號是1~n
    for (int i = 1; i <= n; i ++ )
    {
        p[i] = i;
        size[i] = 1;
    }

    // 合併a和b所在的兩個集合:
    size[find(b)] += size[find(a)];
    p[find(a)] = find(b);


(3)維護到祖宗節點距離的並查集:

    int p[N], d[N];
    //p[]儲存每個點的祖宗節點, d[x]儲存x到p[x]的距離

    // 返回x的祖宗節點
    int find(int x)
    {
        if (p[x] != x)
        {
            int u = find(p[x]);
            d[x] += d[p[x]];
            p[x] = u;
        }
        return p[x];
    }

    // 初始化,假定節點編號是1~n
    for (int i = 1; i <= n; i ++ )
    {
        p[i] = i;
        d[i] = 0;
    }

    // 合併a和b所在的兩個集合:
    p[find(a)] = find(b);
    d[find(a)] = distance; // 根據具體問題,初始化find(a)的偏移量