查询字符串
查询字符串
给定 个字符串 。
这些字符串两两不同。
下面给定 个询问。
其中,第 次询问给定一个字符串 ,你的任务是:
- 计算 这 个字符串中,包含 作为子串的字符串的数量。
- 从 这 个字符串中,任选一个包含 作为子串的字符串输出。
输入格式
第一行包含整数 。
接下来 行,其中第 行包含字符串 。
再一行包含整数 。
接下来 行,其中第 行包含字符串 。
所有 和 都只包含小写字母、数字以及 . 。
输出格式
共 行,其中第 行输出第 个询问的答案。
首先输出 这 个字符串中包含 作为子串的字符串的数量。
然后从 这 个字符串中任选一个包含 作为子串的字符串输出。
如果这样的字符串不唯一,则输出任意合理字符串均可,如果这样的字符串不存在,则输出 - 。
数据范围
前三个测试点满足 。
所有测试点满足 ,,。
输入样例:
4 test contests test. .test 6 ts . st. .test contes. st
输出样例:
1 contests 2 .test 1 test. 1 .test 0 - 4 test.
解题思路
这题并没有很复杂,突破口是字符串长度的数据范围,每个字符串最大的出度不超过。因为题目查询的是某个子串的出现次数,所以我们可以想到,因为每个字符串的长度很小,因此字符串对应的字串数量也很少(假设字符串的长度为,那么这个字符串包含的子串个数为,如果,最多也只有个子串)。我们可以把每个字符串的子串存下来,查询的时候在这些子串中查找。
因此我们可以开两个哈希表,一个用来统计对于某个子串有多少个字符串包含这个子串,另一个用来记录某个子串对应哪个字符串(任意一个包含这个子串的字符串)。
AC代码如下:
1 #include <cstdio> 2 #include <unordered_map> 3 #include <unordered_set> 4 #include <string> 5 #include <algorithm> 6 using namespace std; 7 8 unordered_map<string, int> cnt; 9 unordered_map<string, string> mp; 10 11 int main() { 12 int n; 13 scanf("%d", &n); 14 for (int i = 0; i < n; i++) { 15 char s[10]; 16 scanf("%s", s); 17 18 string str = s; 19 unordered_set<string> st; // 用来判重,如果某个字符串包含多个相同的子串,只记录一次。例如:aaaaa 20 for (int len = 0; s[len]; len++) { 21 for (int i = 0; s[i + len]; i++) { 22 string t = str.substr(i, len + 1); 23 if (!st.count(t)) { 24 cnt[t]++; 25 mp[t] = str; 26 st.insert(t); 27 } 28 } 29 } 30 } 31 32 int m; 33 scanf("%d", &m); 34 while (m--) { 35 char s[10]; 36 scanf("%s", s); 37 printf("%d %s\n", cnt[s], mp.count(s) ? mp[s].c_str() : "-"); 38 } 39 40 return 0; 41 }
因为是查找字符串,我们也可以用trie把所有的子串存下来,然后进行查找。
AC代码如下:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int N = 5e5 + 10, M = 1 << 8; // 粗略计算,一个字符串的所有子串最多会用到50个字符 7 8 int trie[N][M], cnt[N], idx; 9 char mp[N][10]; 10 11 void insert(char *s, char *str) { 12 int p = 0; 13 for (int i = 0; s[i]; i++) { 14 int t = s[i]; 15 if (trie[p][t] == 0) trie[p][t] = ++idx; 16 p = trie[p][t]; 17 } 18 19 cnt[p]++; 20 strcpy(mp[p], str); 21 } 22 23 int query(string s) { 24 int p = 0; 25 for (int i = 0; s[i]; i++) { 26 int t = s[i]; 27 if (trie[p][t] == 0) return 0; 28 p = trie[p][t]; 29 } 30 31 return p; 32 } 33 34 int main() { 35 int n; 36 scanf("%d", &n); 37 while (n--) { 38 char str[10]; 39 scanf("%s", str); 40 41 for (int i = 0; str[i]; i++) { 42 for (int j = 0; j <= i; j++) { 43 char s[10] = {0}; // 记得初始化0,memcpy函数后面不会补0 44 memcpy(s, str + j, i - j + 1); 45 if (strcmp(mp[query(s)], str)) insert(s, str); // 对于当前的字符串,如果某个子串出现过,那么就不可以再统计这个字符串了 46 } 47 } 48 } 49 50 int m; 51 scanf("%d", &m); 52 while (m--) { 53 char str[10]; 54 scanf("%s", str); 55 56 int t = query(str); 57 if (cnt[t]) printf("%d %s\n", cnt[t], mp[t]); 58 else printf("0 -\n"); 59 } 60 61 return 0; 62 }
参考资料
AcWing 4398. 查询字符串(AcWing杯 - 周赛):https://www.acwing.com/video/3789/
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/16142075.html
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
2021-04-13 Saving James Bond - Hard Version