// 题意: 给出N(<=100000)个带通配符(?和*)的模式串, M(<=100)个字符串,
// '*'可代替0个或多个字母,'?'可代替一个字母,问每个字符串能匹配到哪些模式串,按顺序给出
// 模式串长度不超过6, 要匹配的字符串长度不超过20.
// 思路: 用trie树动态构建模式串,然后再dfs来匹配,
// 要注意若静态建树会 MLE ,因为每个节点都含有vector<int>
#include <iostream> // trie树, 含通配符的多字符串匹配
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
struct Node //动态建树
{
Node* next[28]; //26个小写字母加上'?'、'*'
vector<int> pattern; //标记该节点所代表的字符串是哪些模式串
Node()
{
memset(next,NULL,sizeof(next));
}
};
Node* root=new Node();
void insert(char ch[],int pos)
{
Node* p=root;
for(int i = 0; ch[i]; ++i)
{
int j;
if(ch[i] == '?')
j = 26;
else if(ch[i] == '*')
j = 27;
else
j = ch[i] - 'a';
if(p->next[j]==NULL)
{
p->next[j]=new Node();
}
p=p->next[j];
}
p->pattern.push_back(pos);
}
vector <int> ans;
void dfs(char ch[], int k,Node* p) //当前位置是在节点p,要查找的字符ch[k]
{
if(ch[k] == '\0') //该字符串查找完毕
{
while(p!=NULL)
{
int rear=p->pattern.size();
for(int i=0;i<rear;++i)
ans.push_back(p->pattern[i]);
p=p->next[27]; // 因为*通配符可以当作0个字符
}
}
else
{
Node* q;
q=p->next[ch[k]-'a'];
if(q!=NULL)
dfs(ch,k+1,q);
q=p->next[26]; //模式串当前位置上的字符是?
if(q!=NULL)
dfs(ch,k+1,q);
q=p->next[27]; //模式串当前位置上的字符是*
if(q!=NULL)
{
for(;k<=strlen(ch);++k) // *通配符可以匹配任意个字符
dfs(ch,k,q);
}
}
}
int main()
{
int n, m;
char ch[22];
scanf("%d %d", &n, &m);
for(int i=0;i<n;++i)
{
scanf("%s",ch);
insert(ch,i);
}
while(m--)
{
scanf("%s", ch);
ans.clear();
dfs(ch,0,root); //从根结点开始搜索
if(ans.empty())
{
printf("Not match\n");
}
else
{
//用vector来存储结果,排序后再处理掉重复元素,时间上还是比set有优势
sort(ans.begin(),ans.end());
printf("%d ",ans[0]);
int rear=ans.size();
for(int i=1;i<rear;++i)
{
if(ans[i]!=ans[i-1])
printf("%d ",ans[i]);
}
printf("\n");
}
}
return 0;
}