Poj 1451 JAVA 个人解题报告

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分钟就解决了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值