牛客网 HDU 1298 T9
字典树用于存储字典中各单词以及权值(可能性),每个节点只存储字符和权值,这是最简单的一种情况。而实际上还可以存储是否为单词结尾,有多少单词用作前缀等。
输入:
hell 3
hello 4
idea 8
next 8
super 3
相同的前缀其权值相加,根据这个输入建立的字典树为:
对于按键盘上43556这几个数字,首先4对应ghi,hi都在字典树中存在,且i的权值为8,应该优先显示。然后3对应def,和hi组合有id、ie、if、hd、he、hf,其中只有he和id存在,且id的权值为8(根据d的权值),而he的权值为7,所以优先显示id。之后类推。
输入:
abyb 3
abye 13
aaza 4
建立的字典树为:
对于2292来说,当摁完229,aby的权值最大为16,而aaz的权值为4。当摁完最后一个2,abyb的权值为3,而aaza的权值为4,所以应该显示aaza。
代码:
import java.util.*;
import java.io.*;
import static java.lang.System.out;
public class Main {
public Node root = null;//根节点
public Main() {
this.root = new Node();
}
public void insert(String str, int weight) {//插入单词,维护字典树的各节点权值
Node cur = this.root;
for (char c: str.toCharArray()) {
int index = c - 'a';
if (cur.son[index] == null) {
cur.son[index] = new Node(c, weight);
} else {
cur.son[index].weight += weight;//权值相加
}
cur = cur.son[index];
}
}
public Comparator<String> comparator = new Comparator<String>() {//用于PriorityQueue的接口实现,根据字符串前缀的权值比较,权值大的要排在队头
@Override
public int compare(String o1, String o2) {
// TODO Auto-generated method stub
int w1 = search(o1), w2 = search(o2);
if (w1 > w2) return -1;//根据字符串前缀的权值比较,权值大的要排在队头,返回-1表名要排在前面,即靠近队头
else if (w1 < w2) return 1;
else return 0;
}
};
PriorityQueue<String> queue = new PriorityQueue<>(comparator);
LinkedList<String> list = new LinkedList<>();//普通队列,用广度优先遍历存储各种可能的组合
public String[] map = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
public void out(String digit) {
list.clear();
list.add("");
for (int i = 0; i < digit.length(); i++) {
int index = digit.charAt(i) - '0';
while (!list.isEmpty() && list.peek().length() == i) {
String s = list.removeFirst();
for (char c:map[index].toCharArray())
if (search(s + c) != 0) list.add(s + c);//如果在字典树中存在,就加入普通队列
}
queue.clear();
queue.addAll(list);//将普通队列的元素加入到PriorityQueue,让PriorityQueue自动帮我们找到权值最大的那个前缀,我们就不用自己手动写代码去找了
if (!queue.isEmpty()) System.out.println(queue.peek());
else System.out.println("MANUALLY");
}
}
public int search(String string) {//返回该前缀的权重
Node cur = this.root;
for (char c: string.toCharArray()) {
int index = c - 'a';
if (cur.son[index] == null) return 0;
else cur = cur.son[index];
}
return cur.weight;//权重是最后一个字符的权重
}
public static void main(String[] args) throws Exception{//读取输入并产生输出
//还需要优化,因为不能将下面这些代码放在主方法里,而应该另外封装一个读取输入并产生输出的方法
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
int scenario = Integer.parseInt(bufferedReader.readLine());
for (int i = 1; i <= scenario; i++) {
Main t = new Main();
out.println("Scenario #" + i + ":");
int createWord = Integer.parseInt(bufferedReader.readLine());
for (int j = 0; j < createWord; j++) {
String[] data = bufferedReader.readLine().split(" ");
t.insert(data[0], Integer.parseInt(data[1]));
}
int intelligent = Integer.parseInt(bufferedReader.readLine());
for (int k = 0; k < intelligent; k++) {
String s = bufferedReader.readLine();
t.out(s.substring(0, s.length() - 1));
out.println();
}
out.println();
}
}
}
class Node {//节点类
public Node[] son;//每个节点有26个子节点,只考虑小写字母的情况
public int weight;//权值
public char value;//存放的字符
public Node () {
son = new Node[26];
}
public Node(char value, int weight) {
son = new Node[26];
this.value = value;
this.weight = weight;
}
}