题意:
给出n个模式串,串中除开小写字母外,’?’代表一个字符,’*’代表可空的任意字符串,然后再给出m个字符串,问有多少个模式串可以与之匹配。
解析:
可以通过模式串建立字典树,接着根据字符串去dfs就行了。
需要注意的就是遇到当前节点为*则还可以继续走当前结点,每次dfs要么字典树匹配深度加1,要么字符串位置加1,记录每个结点保存模式串的终点的编号,建一个邻接表储存各个结点的模式串信息。
my code
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define pb push_back
using namespace std;
const int MAXN = 1e5 + 10;
const int maxnode = 6e5 + 10;
const int sigma_size = 28;
bool vis[MAXN];
vector<int> ans;
struct Trie {
int ch[maxnode][sigma_size];
char alpha[maxnode];
vector<int> val[maxnode];
int sz;
void clear() { sz = 1; memset(ch[0], 0, sizeof(ch[0])); }
Trie() { clear(); }
inline int idx(char c) {
if(c == '?') return 26;
else if(c == '*') return 27;
return c - 'a';
}
void insert(char *s, int v) {
int u = 0, n = strlen(s);
for(int i = 0; i < n; i++) {
int c = idx(s[i]);
if(!ch[u][c]) {
memset(ch[sz], 0, sizeof(ch[sz]));
alpha[sz] = s[i];
val[sz].clear();
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u].pb(v);
}
void dfs(char* s, int u) {
if(*s == '\0') {
for(int i = 0; i < val[u].size(); i++) {
int tmp = val[u][i];
if(!vis[tmp]) {
vis[tmp] = true;
ans.pb(tmp);
}
}
if(ch[u][27]) dfs(s, ch[u][27]);
return ;
}
int c = idx(*s);
if(ch[u][c])
dfs(s+1, ch[u][c]);
if(ch[u][26])
dfs(s+1, ch[u][26]);
if(ch[u][27]) {
dfs(s+1, ch[u][27]);
dfs(s, ch[u][27]);
}
if(alpha[u] == '*')
dfs(s+1, u);
}
} trie;
void output() {
sort(ans.begin(), ans.end());
printf("%d", ans[0]);
for(int i = 1; i < ans.size(); i++)
printf(" %d", ans[i]);
puts("");
}
char str[20];
int n, m;
int main() {
while(scanf("%d%d", &n, &m) != EOF) {
trie.clear();
for(int i = 0; i < n; i++) {
scanf("%s", str);
trie.insert(str, i);
}
for(int i = 0; i < m; i++) {
scanf("%s", str);
memset(vis, false, sizeof(vis));
ans.clear();
trie.dfs(str, 0);
int size = ans.size();
if(size > 0) output();
else puts("Not match");
}
}
return 0;
}