KMP,trie樹,並查集
阿新 • • 發佈:2022-03-18
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)的偏移量