思路:字典树
分析:
1 题目要求的是给以个询问字符串s,在n个物品中找到总共有几个满足s是物品名字的字串。
2 子串问题,那么这里我们可以利用求出n件物品名字的所有的字串(这里要扣除重复),然后建立字典树,最后求总共有几个即可。
3 这个第一个是怎么判断一个字符串的子串已经有了,即假设有字符串“abab”,那么子串“ab”将出现两次,但是只能加1次,所以我们在字典树的节点里面增加一个number,表示当前所要添加的子串来自第几个物品,只要当前的id与节点的number不同就可以加1.
代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
#define MAXN 1000010
#define N 30
int n , q , cnt;
struct Trie{
int number;/*用来记录编号*/
int count;/*count记录单词的个数*/
Trie* child[N];
}trie[MAXN];
Trie *root;
/*静态分配空间*/
Trie* newTrie(){
trie[cnt].number = 0;
trie[cnt].count = 0;
for(int i = 0 ; i < N ; i++)
trie[cnt].child[i] = NULL;
return &trie[cnt++];
}
/*字典树的插入*/
void insert(char *str , int n){
Trie *s = root;
int len = strlen(str);
for(int i = 0 ; i < len ; i++){
int num = str[i]-'a';
if(s->child[num] == NULL)
s->child[num] = newTrie();
s = s->child[num];
}
if(s->number != n){/*如果当前的number和n不同说明可以加1*/
s->count++;
s->number = n;/*把number改为n*/
}
}
/*字典树的查找*/
int search(char *str){
Trie *s = root;
int len = strlen(str);
for(int i = 0 ; i < len ; i++){
int num = str[i]-'a';
if(s->child[num] == NULL)
return 0;
s = s->child[num];
}
return s->count;/*返回总共有几个*/
}
int main(){
root = newTrie();
scanf("%d" , &n);
int cnt;
char ch[N] , words[N] , query[N];
for(int i = 0 ; i < n ; i++){
scanf("%s" , words);
int len = strlen(words);
for(int j = 0 ; j < len ; j++){
memset(ch , '\0' , sizeof(ch));
cnt = 0;
for(int k = j ; k < len ; k++){
ch[cnt++] = words[k];
insert(ch , i+1);
}
}
}
scanf("%d" , &q);
for(int i = 0 ; i < q ; i++){
scanf("%s" , query);
printf("%d\n" , search(query));
}
return 0;
}