POJ - 1816 Wild Words(字典树 + 搜索)

14 篇文章 0 订阅
11 篇文章 0 订阅

POJ - 1816 Wild Words(字典树 + 搜索)

A word is a string of lowercases. A word pattern is a string of lowercases, '?'s and ‘'s. In a pattern, a ‘?’ matches any single lowercase, and a '’ matches none or more lowercases.

There are many word patterns and some words in your hand. For each word, your task is to tell which patterns match it.
Input
The first line of input contains two integers N (0 < N <= 100000) and M (0 < M <=100), representing the number of word patterns and the number of words. Each of the following N lines contains a word pattern, assuming all the patterns are numbered from 0 to N-1. After those, each of the last M lines contains a word.

You can assume that the length of patterns will not exceed 6, and the length of words will not exceed 20.
Output
For each word, print a line contains the numbers of matched patterns by increasing order. Each number is followed by a single blank. If there is no pattern that can match the word, print “Not match”.
Sample Input
5 4
t*
?hs
??e

*s
?*e
this
the
an
is
Sample Output
0 1 3
0 2 4
Not match
3

题目大意:

给你n个单词,m个询问
n个单词,其中每个单词有字母和符号组成,符号只有两种,?可以代表任意一个字母,*可以代表任意长度的一串字母。
给你m个询问,问这个单词最多和上面的几个单词匹配。

解题思路:

字典树上跑dfs
首先 add函数中需要稍微修改一下,因为多了? 和 * 所以我们把他们看做第26个和27个字符(a-z分别是0-25). 然后还加了一个p数组,这个p[i] 表示 第i个单词 最后一个字母的编号。
void find(char *s,int num,int pos) 把find函数写成深搜形式
num就是表示当前这个字符的编号是啥,pos表示到这个s的第几个字符了。
退出条件就是pos大于字符串的长度了。
if(pos == len && flag[num]) 这个表示当前这个是某一个单词的最后一个,并且当前查询的单词也正好到结尾了。换句话说就是匹配上了,就用个 vis数组标记一下这个编号。

特判一下? *
*他可以代表任意长度的字符,所以他的pos能跳到任何位置。
?代表任意一个字符,所以他能跳到 pos+1的位置。

if(tree[root][26]){///到*
		for(int j=pos;j<=len;j++){
			find(s,tree[root][26],j);
		}
	}
	if(tree[root][27]){//到?
		find(s,tree[root][27],pos+1);
	}

然后就是普通字符了,直接向下走就行了 当然得判断一下他的下一个是否为字母。

if(tree[root][id]&&s[pos]>='a'&&s[pos]<='z'){
		find(s,tree[root][id],pos+1);
	}

这样对每个询问,我们都跑一遍这个find 然后时候是否和前面的n个单词匹配上。

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
const int maxn = 2e6+10;
int tree[maxn][30];//30取决于字母的个数,第i个节点的第j个孩子
int tot = 0;
int sum[maxn];
bool flag[maxn];//标号为i的是否为一个字符串的最后一个
int n,q;
int vis[maxn];
int p[maxn];//p[i]表示第i个字符串的尾结点是 啥
void add(char *s,int x){
	int root = 0;
	int id;
	int len = strlen(s);
	for(int i=0;i<len;i++){
		if(s[i] == '*') id = 26;
		else if(s[i] == '?') id = 27;
		else id = s[i]-'a';//这个字母是几
		if(!tree[root][id]) tree[root][id] = ++tot;
		root = tree[root][id];
		sum[tot]++;
	}
	p[x] = root;
	flag[root] = true;//这是个字符串
}
void find(char *s,int num,int pos){
	int len = strlen(s);
	int id;
	int root = num;
	if(pos>strlen(s)) return;
	if(pos == len && flag[num]){
		vis[root] = 1;
	//	return ;
	}
	if(tree[root][26]){///到*
		for(int j=pos;j<=len;j++){
			find(s,tree[root][26],j);
		}
	}
	if(tree[root][27]){//到?
		find(s,tree[root][27],pos+1);
	}
	id = s[pos] - 'a';
	if(tree[root][id]&&s[pos]>='a'&&s[pos]<='z'){
		find(s,tree[root][id],pos+1);
	}
}
char s[maxn];
int main(){
	scanf("%d%d",&n,&q);
	for(int i=0;i<n;i++){
		scanf("%s",s);
		add(s,i);
	}
	for(int i=0;i<q;i++){
		memset(vis,0,sizeof(vis));
		scanf("%s",s);
		find(s,0,0);
		int tt = 0;
		for(int j=0;j<n;j++){
			if(vis[p[j]]){
				tt = 1;
				cout<<j<<" ";
			}
		}
		if(!tt) puts("Not match");
		else printf("\n");
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值