Loading

字典树

字典树(Trie)

先看一张图(来自 oi-wiki):

我们让每条边都代表一个字母,所以从根结点到任意一个结点的路径都是一个字符串。

因此,我们需要一个数组来记录每个结点是否有某条代表字母 \(c\) 的边,如果没有,就加上这条边,否则,直接跳到这条边指向的结点。

查找字符串

查询某个字符串是否出现过。

Trie 的时间复杂度为 \(O(n)\)\(n\) 代表所有字符串的字符总数。

暴力

把所有字符串存到 mapset 中,判断是否出现过。

(其实好像不算暴力)

正解

对所有字符串建 Trie,再在 Trie 中查询。

#include <bits/stdc++.h>

using namespace std;

const int N = 5e5 + 10;

int n, m, f[N][30], c;
bool v[N], vis[N];

void Insert(string s) {
  int root = 0;
  for (int i = 0; i < s.size(); i++) {
    if (!f[root][s[i] - 'a']) {
      f[root][s[i] - 'a'] = ++c;
    }
    root = f[root][s[i] - 'a'];
  }
  v[root] = 1;   // 从根结点到 root 的路径是一个字符串
}

void Find(string s) {
  int root = 0;
  for (int i = 0; i < s.size(); i++) {
    root = f[root][s[i] - 'a'];
    if (!root) {  // 找不到了
      cout << "WRONG\n";
      return ;
    }
  }
  if (!v[root]) {
    cout << "WRONG\n";
  } else {
    cout << "OK\n";
  }
}

int main() {
  ios::sync_with_stdio(0), cin.tie(0);
  cin >> n;
  while (n--) {
    string s;
    cin >> s, Insert(s);
  }
  cin >> m;
  while (m--) {
    string s;
    cin >> s, Find(s);
  }
  return 0;
}

同样的,我们可以用字典树查找当前字符串是不是某个字符串的前缀。

#include <bits/stdc++.h>

using namespace std;

const int N = 3e6 + 10;

int T, n, q, c, sz[N], f[N][75];

int ID(char a) {
  return 'a' <= a && a <= 'z' ? a - 'a' : ('A' <= a && a <= 'Z' ? 26 + a - 'A' : 52 + a - '0');
}

void Insert(string s) {
  int root = 0;
  for (int i = 0; i < s.size(); i++) {
    int t = ID(s[i]);
    if (!f[root][t]) {
      f[root][t] = ++c;
    }
    root = f[root][t], sz[root]++;  // sz 表示从跟结点到 root 是这条路径是多少个字符串的前缀
  }
}

void Find(string s) {
  int root = 0;
  for (int i = 0; i < s.size(); i++) {
    root = f[root][ID(s[i])];
    if (!root) {
      break;
    }
  }
  cout << sz[root] << '\n';
}

void Solve() {
  cin >> n >> q, c = 0;
  while (n--) {
    string s;
    cin >> s, Insert(s);
  }
  while (q--) {
    string s;
    cin >> s, Find(s);
  }
  for (int i = 0; i <= c; i++) {
    for (int j = 0; j < 75; j++) {
      f[i][j] = 0;
    }
    sz[i] = 0;
  }
}

int main() {
  ios::sync_with_stdio(0), cin.tie(0);
  cin >> T;
  while (T--) {
    Solve();
  }
  return 0;
}
posted @ 2025-05-04 10:13  Yan719  阅读(21)  评论(0)    收藏  举报