1 条题解
-
1
做法有很多种,这里介绍一个算法, 树(字典树)。
树是一个很方便的存储字符串的数据结构。
首先,我们定义
vector ch(n, vector<char>(26));//记录字符串的二维数组,第二维度是26,因为有26个字母,我们将a-z映射到0-25 vector cnt(n); int idx = 0;
数组通过树形结构负责记录字符串
则是代表树的节点编号
数组在每个字符串末尾的序号处加 代表存在这个字符串。
例如, 建立的字典树如图所示:
这里 代表从节点 到节点 的这条边存在一条边存储着 这个字符, 存储的则是 这个字符,这里的 第二维度中的 是通过让字符减去 这个偏移量映射的 。
代表存在一个以这条边上的字符 结尾的字符串,其他 处同理。
接下来介绍 树的代码:
void insert(string s) { int u = 0; for(int i = 0; i < s.size(); i ++) { int v = s[i] - 'a'; if(!ch[u][v]) ch[u][v] = ++idx;//如果没有这个点,我们就创建这个点,并且记录其编号为0,1...n-1,n u = ch[u][v];//如果存在这个点,我们就将u修改为边的起点 } cnt[u] ++;//记录以u这条边上的字符为结尾的字符串 } ll query(string s) { int u = 0; for(int i = 0; i < s.size(); i ++) { int v = s[i] - 'a'; if(!ch[u][v]) return 0;//如果不存在这个点,返回0 u = ch[u][v];//如果存在这个点 } return cnt[u];//存在这个点就返回,看是否有以u为终点的字符串 }
分析 树的时间复杂度:
最多是所有节点都不重复,那么就是每个字符串的字符都对应一个点,总节点数等于所有字符串长度的总和,一共有 个字符,时间复杂度即为 这里的 代表所有字符串的长度。
拓展, 树能做的还有很多,可以映射 ,只要修改映射值,就能存储其他东西。
这里贴一个 树的板子
struct Trie { std::map<char, int> mp; int idx = 0; std::vector<std::vector<int>> ch; std::vector<int> cnt; Trie(int n) { ch.resize(n, std::vector<int>(63)); cnt.resize(n); idx = 0; ll id = 0; for(char c = 'a'; c <= 'z'; c ++) mp[c] = ++id; for(char c = 'A'; c <= 'Z'; c ++) mp[c] = ++id; for(char c = '0'; c <= '9'; c ++) mp[c] = ++id; } void insert(std::string s) { int u = 0; for(int i = 0; i < s.size(); i ++) { int v = mp[s[i]]; if(!ch[u][v]) ch[u][v] = ++idx; u = ch[u][v]; } cnt[u] ++; } ll query(std::string s) { int u = 0; for(int i = 0; i < s.size(); i ++) { int v = mp[s[i]]; if(!ch[u][v]) return 0; u = ch[u][v]; } return cnt[u]; } //清空函数 void clear() { for(int i = 0; i <= idx; i ++) { cnt[i] = 0; for(int j = 0; j <= 62; i ++) { ch[i][j] = 0; } } idx = 0; } }; //Trie的遍历 function<void(int, int)> dfs = [&](int p, int ans) { ans += cnt[p]; bool f = 1; for(int i = 0; i < 26; i ++) { if(ch[p][i]) { dfs(ch[p][i], ans), f = false; } } if(f) { anss = max(anss, ans); } }; //调用板子 Trie t(N);
对于这道题目,只需要用 树记录名单,再开一个 数组映射,每次询问的时候,在 中记录该询问的字符串,如果询问的字符串在 树上存在,且未在 中出现,则 ,若在树上存在,在 中出现过,则 ,若在树上不存在,则 。
#include <bits/stdc++.h> using namespace std; using ll = long long; constexpr int N = 500010; signed main() { int n; cin >> n; int idx = 0; vector<int> cnt(N); vector ch(N, vector<int>(26)); auto insert = [&](string s) { int p = 0; for(int i = 0; i < s.size(); i ++) { int j = s[i] - 'a'; if(!ch[p][j]) ch[p][j] = ++idx; p = ch[p][j]; } cnt[p] ++; }; auto query = [&](string s) { int p = 0; for(int i = 0; i < s.size(); i ++) { int j = s[i] - 'a'; if(!ch[p][j]) return 0; p = ch[p][j]; } return cnt[p]; }; while(n --) { string s; cin >> s; insert(s); } map<string, int> ma; int m; cin >> m; while(m --) { string s; cin >> s; int f = query(s); // cout << f << endl; if(f != 0 && ma[s] == 0) { cout << "OK" << endl; } else if(f != 0 && ma[s] != 0) { cout << "REPEAT" << endl; } else if(f == 0) { cout << "WRONG" << endl; } ma[s] ++; } }
ps:如果不熟悉 可以做下洛谷上的 这道题
- 1
信息
- ID
- 95
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 7
- 标签
- 递交数
- 24
- 已通过
- 9
- 上传者