题目描述:
对若干行文字建立倒排索引(根据单词找到所在行号)。
然后根据关键字,在倒排索引查找进行查找,找到包含所有该关键字所在的行数并输出。
输入说明
- 若干行英文,以
!!!!!
为结束。 - 输入一行查询关键字,以1个空格为分隔
输出说明
- 输出所创建倒排索引。索引的key按照字母升序,索引的value按照行号升序
- 输出查询结果。如果找到,输出行集与行集内每一行的内容,如果没找到输出
found 0 results
输入样例
where are you from are you ok
this is a test
that is an apple
there are lots of apples you eat it
who are you
!!!!!
you are
eat
you test
abc
输出样例
a=[2]
an=[3]
apple=[3]
apples=[4]
are=[1, 4, 5]
eat=[4]
from=[1]
is=[2, 3]
it=[4]
lots=[4]
of=[4]
ok=[1]
test=[2]
that=[3]
there=[4]
this=[2]
where=[1]
who=[5]
you=[1, 4, 5]
[1, 4, 5]
line 1:where are you from are you ok
line 4:there are lots of apples you eat it
line 5:who are you
[4]
line 4:there are lots of apples you eat it
found 0 results
found 0 results
题目分析:
由于题目要求从句段中提取出单词和其所在行号,且单词拥有不重复的特性。因此考虑采用拥有键值对的Map集合。
输入句子时为了区分空格与换行,考虑采用nextLine方法。
为了将每句话的单词提取出来,使用split方法将String句子拆分为单词。
因为该程序要实现的功能较为复杂,故准备定义多个类。
设计重点:
1.如何存储复杂的单词信息:一开始只是想用Map集合分别存储单词的内容和位置,然而由于同一个单词可能会出现在多个不同位置,因此值的类型又是一个TreeSet集合,因此这是一个嵌套集合。
TreeMap<String, TreeSet<Integer>> map = new TreeMap<>();//记录单词内容和出现句子
2.为什么split把句子拆成了字母:由于regex分隔符是用来识别哪里开始拆的,因此需要在分隔符
“ ”中加入空格,句子会在每个空格处拆开变成单词。
3.如何提取出两个单词共同存在的句子:要实现这个功能非常麻烦。通过建立两个集合分别存储每个单词所在句子和共同所在句子的方式,实现了这个方法。
最终代码:
import java.util.ArrayList;
import java.util.Scanner;
import java.util.TreeMap;
import java.util.TreeSet;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
boolean s1 = false;
int n = 1;//输入的句子数
addtoMap add = new addtoMap();//该类用于将句子转化为单词信息并存储
ArrayList<String> arr = new ArrayList<>();//用于储存每句话的信息
//第一步:输入句子
while (s1 == false) {
String sentence = sc.nextLine(); //输入句子直至出现"!!!!!"为止
if (sentence.equals("!!!!!")) {
s1 = true;
break;
}
arr.add(sentence);
String words[] = sentence.split(" ");//将句子转入数组
add.Add(words, n);
n++;
}
add.map.forEach((String k, TreeSet val) -> System.out.println(k + "=" + val));
//第二步:查找单词
boolean s2 = false;
while(s2==false) {
String sentence = sc.nextLine(); //输入句子直至出现"abc"为止
ArrayList<Integer> A = add.Check(sentence);
if (A.isEmpty()) {
System.out.println("found 0 results");
} else {
System.out.println(A);
for (int i = 0; i < A.size(); i++) {
int m = A.get(i);
System.out.println("line "+m+":"+arr.get(m - 1));
}
}
}
}
}
class addtoMap {
TreeMap<String, TreeSet<Integer>> map = new TreeMap<>();//记录单词内容和出现句子
public void Add(String[] w, int i) {
boolean S = false;
for (int j = 0; j < w.length; j++) {
if (map.containsKey(w[j])) {
TreeSet<Integer> num = map.get(w[j]);//通过单词找存储句子的集合(键找值)
num.add(i);
map.put(w[j], num);
} else {
TreeSet<Integer> num = new TreeSet<>();//记录出现的句子号数
num.add(i);
map.put(w[j], num);
}
}
}
public ArrayList Check(String h) {
TreeSet<Integer> keysentence = new TreeSet<>(); // 先将每个关键词对应的句子存储
ArrayList<Integer> realsentence = new ArrayList<>(); //再将有重叠句子的单独存储
String keyword[] = h.split(" ");//将句子转入数组
for (int i = 0; i < keyword.length; i++) {
if (map.containsKey(keyword[i])) {
TreeSet<Integer> num = map.get(keyword[i]);//键找值
for (int n : num) { //遍历储存句子序号的集合
if (keysentence.add(n) == false || keyword.length == 1) {
realsentence.add(n);
}
}
}
}
return realsentence;
}
}
由于未知原因,运行范例时结果完全正确,但有一个测试点答案错误。
总结:该题目较有难度。考察对集合各种方法的应用和代码多重复杂功能的实现。