AC 时间 334ms,内存 3000k
题目大意: 模拟手机键盘的九宫格输入模式,每当输入单词,就会显示可能的单词, 根据每个单词的可能性。 这个可能性就是输入列表里跟随每个单词后面的那个正整数。
单词前缀一致的情况下,可能性可以叠加,且只在公用的前缀的字符上叠加, 分支的字符是保持原样的。 按照一定顺序的数字输入, 输出所有可能性的组合。
解题思路: 和前缀有关,字典树是比较快捷的方式。 构造树, 实现插入和查找方法,读取然后输出即可。 我用了一个prob数组 和 ans数组存储可能的组合,2个数组的数据是同步的, 即ans数组n位的字符组合对应prob数组的可能性(输入字符串后的正整数或几个字符串后的正整数之和)。 所以只要按照字典顺序遍历字典树,看见字符就存入ans数组,然后把这串字符串末尾的可能性存入prob数组。 要比较分支谁的可能性大,直接比较prob数组里对应ans数组里index的位置即可,大于数组里的就替换掉即可。
关于怎么把字符串存入ans数组,我是这样做的: 因为是可能的字符串,所以不用设置isWord变量,每一个
package TrieTree;
import java.util.Scanner;
public class Poj1451
{
public static void main(String[] args)
{
String[] ans = null;
Trie3 t = new Trie3();
Scanner scan = new Scanner(System.in);
char[] comb = null;
int times = scan.nextInt(), nums = 0, s = 1;
while(times-- > 0)
{
nums = scan.nextInt();
while(nums-- > 0)
t.add(scan.next(), scan.nextInt());
nums = scan.nextInt();
System.out.println("Scenario #" + s++ + ":");
while(nums-- > 0)
{
comb = scan.next().toCharArray();
ans = new String[comb.length - 1];
t.dfs(comb, ans, 0);
for(int i = 0, len = comb.length - 1; i < len; i++)
{
if(ans[i] == null) System.out.println("MANUALLY");
else System.out.println(ans[i]);
}
System.out.println();
}
System.out.println();
ans = null;
t.clear();
}
}
}
class Trie3
{
public String pad[] = {" ", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
public int[] prob;
public static final int MAX = 26;
public Node root;
class Node
{
Node[] son;
char val;
int prob;
String word = "";
public Node()
{
son = new Node[MAX];
}
}
public Trie3()
{
root = new Node();
prob = new int[100];
}
public void clear()
{
root = null;
root = new Node();
}
public void add(String str, int prob)
{
int pos = 0;
Node node = root;
char[] ls = str.toCharArray();
for(int i = 0; i < ls.length; i++)
{
pos = ls[i] - 'a';
if(node.son[pos] == null)
{
node.son[pos] = new Node();
node.son[pos].val = ls[i];
node.son[pos].word = node.word + ls[i];
}
node = node.son[pos];
node.prob += prob;
}
}
public void dfs(char[] comb, String[] ans, int index)
{
dfs(comb, ans, index, root);
}
public void dfs(char comb[], String[] ans, int index, Node node)
{
int pos = 0, padPos = comb[index] - '1';
if(padPos == 0) return;
Node curr = null;
char[] ls = pad[padPos].toCharArray();
for(int i = 0; i < ls.length; i++)
{
pos = ls[i] - 'a';
curr = node.son[pos];
if(node.son[pos] != null)
{
if(ans[index] != null)
{
if(curr.prob > prob[index])
{
ans[index] = curr.word;
prob[index] = curr.prob;
}
}
else
{
ans[index] = curr.word;
prob[index] = curr.prob;
}
dfs(comb, ans, index + 1, curr);
}
}
}
}
节点就存入从前缀到这个节点的字符,要拿就拿一串设置好的,效率非常的高。
ps:字典树中各个字符出现的可能性是随着树的深度增加而减少的,我一开始没观察到这点,所以写了一大堆条件句去判断哪个可能性更大,简直就是太天真,所以读懂题很重要, 读懂并非读懂, 真正的理解才行, 理解后10分钟就解决了。