题目描述
英语老师留了 NN 篇阅读理解作业,但是每篇英文短文都有很多生词需要查字典,为了节约时间,现在要做个统计,算一算某些生词都在哪几篇短文中出现过。
输入格式
第一行为整数 NN ,表示短文篇数,其中每篇短文只含空格和小写字母。
按下来的 NN 行,每行描述一篇短文。每行的开头是一个整数 LL ,表示这篇短文由 LL 个单词组成。接下来是 LL 个单词,单词之间用一个空格分隔。
然后为一个整数 MM ,表示要做几次询问。后面有 MM 行,每行表示一个要统计的生词。
输出格式
对于每个生词输出一行,统计其在哪几篇短文中出现过,并按从小到大输出短文的序号,序号不应有重复,序号之间用一个空格隔开(注意第一个序号的前面和最后一个序号的后面不应有空格)。如果该单词一直没出现过,则输出一个空行。
输入样例:
3
9 you are a good boy ha ha o yeah
13 o my god you like bleach naruto one piece and so do i
11 but i do not think you will get all the points
5
you
i
o
all
naruto
输出样例:
1 2 3
2 3
1 2
3
2
代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Iterator;
import java.util.TreeSet;
public class Main {
static int tot = 0; //内存池的地址
static Tree tree[]; //trie树
static class Tree {
TreeSet<Integer> set = null; //保存当前单词所在短文的编号,用treeset会自动对文章排序,最后只需要按顺序遍历即可得到有序数列
int next[] = new int[26]; // 保存当前树的26个小写字母
boolean isdanci; //判断当前是否为单词
}
static void insert(int number, char[] c) { //number为当前的短文的编号
int root = 0; //从根节点出发
for (int i = 0; i < c.length; i++) {
//如果当前节点的next[c[i]-'a']为0则表示没有该前缀的单词,我们需要创建
if (tree[root].next[c[i] - 'a'] == 0) {
tree[root].next[c[i] - 'a'] = ++tot; //从内存池中分配新的节点
tree[tot] = new Tree(); //创建对象
root = tot; //从新的节点出发
} else {
root = tree[root].next[c[i] - 'a']; //否则取该节的内存地址
}
}
tree[root].isdanci = true; //设置为单词标记
//如果set为空,表示之前从来没有过该单词,我们为该节点创建新的set对象
if (tree[root].set == null) {
tree[root].set = new TreeSet<>();
}
//将当前的短文编号放入treeset去重
tree[root].set.add(number);
}
static TreeSet<Integer> query(char[] c) {
int root = 0; //从根节点出发
for (int i = 0; i < c.length; i++) {
//若为0,则表示没有该单词,返回null
if (tree[root].next[c[i] - 'a'] == 0)
return null;
//继续找
root = tree[root].next[c[i] - 'a'];
}
//到结尾,如果该串不是单词,则返回空
if (!tree[root].isdanci)
return null;
//返回一个存单词短文编号的序列
return tree[root].set;
}
public static void main(String[] args) throws NumberFormatException, IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(reader.readLine().trim());
tree = new Tree[n * 5000]; //分配空間
tree[0] = new Tree(); //初始化根节点
//初始化字典树
for (int i = 1; i <= n; i++) {
String str[] = reader.readLine().split(" ");
for (int j = 1; j < str.length; j++)
insert(i, str[j].toCharArray());
}
int m = Integer.parseInt(reader.readLine().trim());
StringBuffer sb = new StringBuffer();
for (int i = 0; i < m; i++) {
//从字典树中找到单词所在短文的标号集合
TreeSet<Integer> set = query(reader.readLine().trim().toCharArray());
//如果不为空
if (set != null) {
//set的迭代器
Iterator<Integer> it = set.iterator();
//按顺序输出结果
while (it.hasNext()) {
sb.append(it.next() + " ");
}
}
sb.append("\n");
}
System.out.println(sb);
}
}