AC解 - 统计带某个前缀的单词数量

原题:http://acm.hdu.edu.cn/showproblem.php?pid=1251

Problem Description
Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀).
 
Input
输入数据的第一部分是一张单词表,每行一个单词,单词的长度不超过10,它们代表的是老师交给Ignatius统计的单词,一个空行代表单词表的结束.第二部分是一连串的提问,每行一个提问,每个提问都是一个字符串.

注意:本题只有一组测试数据,处理到文件结束.
 
Output
对于每个提问,给出以该字符串为前缀的单词的数量.
 
Sample Input
banana band bee absolute acm

ba b band abc
Sample Output
2 3 1 0
分析:利用Patricia前缀树(参考另一篇博文),再加一个统计叶子结点(带#终结符)的个数的函数getLeafCount()。

代码:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
 

public class Main {
	private class PatriciaTrieNode {
	    private String key;
	    private Integer data;
	    private List<PatriciaTrieNode> children = new LinkedList<PatriciaTrieNode>();
	    
	    //use "#" for terminal char
	    private boolean terminal; 
	    
	    public PatriciaTrieNode(){	    	
	    	this.key = "";
	    }
	    public PatriciaTrieNode(String key){
	    	this.key = key;	    	
	    }	    
	    public String toString(){	    	
	    	return this.key + (this.terminal?"#":"") + "(" + children.size() +")";
	    }
	}
	private PatriciaTrieNode root;
	//value is only located at the external node
	private void insert(PatriciaTrieNode currNode,String key,Integer value) throws Exception{		
		boolean done = false;
		for(int i=0;i<currNode.children.size();i++){
			PatriciaTrieNode child = currNode.children.get(i);
			
			//use min(child.key.length, key.length)
			int len = child.key.length()<key.length()?child.key.length():
				key.length();
			int j = 0;
			for(;j<len;j++){
				if(key.charAt(j) != child.key.charAt(j)){
					break;
				}
			}
			if(j==0){//this child doesn't match	any character with the new key			
				//order keys by lexi-order
				if(key.charAt(0)<child.key.charAt(0)){
					//e.g. child="e" (currNode="abc")
					//	   abc                     abc
					//    /  \    =========>      / | \
					//   e    f   insert "c"     c# e  f
				
					PatriciaTrieNode node = new PatriciaTrieNode(key);
					currNode.children.add(i,node);
					node.terminal = true;		
					node.data = value;
					done = true;
					break;					
				}else{ //key.charAt(0)>child.key.charAt(0)
					//don't forget to add the largest new key after iterating all children
					continue;
				}
			}else{//current child's key partially matches with the new key; 0<j<=len				
				if(j==len){
					if(key.length()==child.key.length()){
						if(child.terminal){
							throw new Exception("Duplicate Key is found when insertion!");							
						}else{
							//e.g. child="ab"
							//	   ab                    ab#
							//    /  \    =========>    /   \
							//   e    f   insert "ab"  e     f
							child.terminal = true;
							child.data = value;
						}
					}else if(key.length()>child.key.length()){
						//e.g. child="ab#"
						//	   ab#                    ab#
						//    /  \    ==========>    / | \ 							
						//   e    f   insert "abc"  c# e  f						
						String subkey = key.substring(j);
						//recursion
						insert(child,subkey,value);
					}else{ //key.length()<child.key.length()
						//e.g. child="abc#"
						//	   abc#                      ab#
						//    /   \      =========>      /   
						//   e     f     insert "ab"    c#    
						//					           /  \
						//                            e    f													
						String childSubkey = child.key.substring(j); //c
						PatriciaTrieNode subChildNode = new PatriciaTrieNode(childSubkey);
						subChildNode.terminal = child.terminal;
						subChildNode.data = child.data;
						subChildNode.children = child.children; //inherited from parent
						
						child.key = key;  //ab
						child.terminal = true;  //ab#	
						child.data = value;
						
						child.children = new LinkedList<PatriciaTrieNode>();
						child.children.add(subChildNode);
					}					
				}else{//0<j<len
					//e.g. child="abc#"
					//	   abc#                     ab
					//    /  \     ==========>     / \
					//   e    f   insert "abd"    c#  d# 
					//                           /  \
					//                          e    f					
					//split at j
					String childSubkey = child.key.substring(j);  //c
					String subkey = key.substring(j); //d
					
					PatriciaTrieNode subChildNode = new PatriciaTrieNode(childSubkey);
					subChildNode.terminal = child.terminal;
					subChildNode.data = child.data;
					subChildNode.children = child.children; //inherited from parent
					
					//update child's key
					child.key = child.key.substring(0,j);
					//child is not terminal now due to split, it is inherited by subChildNode
					child.terminal = false;
					
					//Note: no need to merge subChildNode					
					
					PatriciaTrieNode node = new PatriciaTrieNode(subkey);
					node.terminal = true;
					node.data = value;
					child.children = new LinkedList<PatriciaTrieNode>();
					if(subkey.charAt(0)<childSubkey.charAt(0)){
						child.children.add(node);
						child.children.add(subChildNode);
					}else{
						child.children.add(subChildNode);
						child.children.add(node);
					}
				}
				done = true;
				break;
			}
		}
		if(!done){
			PatriciaTrieNode node = new PatriciaTrieNode(key);		
			node.terminal = true;
			node.data = value;
			currNode.children.add(node);
		}
	}
	public void insert(String key,Integer value) throws Exception{
		if(key == null || key.length() == 0) return;
		
		if(root==null){
			root = new PatriciaTrieNode();				
		}
		insert(root,key,value);		
	}
	
	public int query(String key){
		return query(root,key);
	}
	
	private int query(PatriciaTrieNode currNode,String key) {
		for(int i=0;i<currNode.children.size();i++){
			PatriciaTrieNode child = currNode.children.get(i);
			
			//use min(child.key.length, key.length)
			int len = child.key.length()<key.length()?child.key.length():
				key.length();
			int j = 0;
			for(;j<len;j++){
				if(key.charAt(j) != child.key.charAt(j)){
					break;
				}
			}
			
			if(j==0){//this child doesn't match	any character with the new key			
				//order keys by lexi-order
				if(key.charAt(0)<child.key.charAt(0)){
					//e.g. child="e", key="c" (currNode="abc")
					//	   abc                     
					//    /  \     
					//   e    h   
					return 0;
				}else{
					//e.g. child="e", key="h" (currNode="abc")
					continue;
				}
			}else{//current child's key partially matches with the new key; 0<j<=len				
				if(j==len){
					if(key.length()==child.key.length()){
						if(child.terminal){
							//e.g. child="ab", key="ab"
							//	   ab#                    
							//       \    
							//        f#    
							return getLeafCount(child);						
						}else{
							//e.g. child="ab", key="ab"
							//	   ab                    
							//    /  \    
							//   e    f    
							return getLeafCount(child);
						}
					}else if(key.length()>child.key.length()){
						//e.g. child="ab#", key="abc"
						//	   ab#                     
						//    /  \     						
						//   a    c#   			
						String subkey = key.substring(j); //c
						//recursion
						return query(child,subkey);
					}else{ //key.length()<child.key.length()
						//e.g. child="abc", key="ab"
						//	   abc                      
						//    /   \       
						//   e     f     
						return getLeafCount(child);						
					}					
				}else{//0<j<len
					//e.g. child="abc", key="abd"
					//	   abc                     
					//    /  \      
					//   e    f    
					return 0;					
				}				
			}
			
		}
		return 0;
	}
	
	public int getLeafCount(PatriciaTrieNode currNode){
		int count = 0;
		if(currNode.terminal)
			count++;
		for(int i=0;i<currNode.children.size();i++){
			PatriciaTrieNode child = currNode.children.get(i);
			count += getLeafCount(child);
		}
		return count;
	}
 
	
	public static void main(String[] args) {
		BufferedReader bf = new  BufferedReader(new InputStreamReader(System.in));
		List<String> queries = null;
		Main main = new Main();
		try{	
			String line = bf.readLine();
			line = line.trim();
			
			while(line.length()>0){
				try {
					main.insert(line, 0);
				} catch (Exception e) {
					
				}
				line = bf.readLine();
				line = line.trim();
			}
			//main.printTree();			
			
			queries = new ArrayList<String>();			
			while((line=bf.readLine())!= null){		
				line = line.trim();
				queries.add(line);
			}
		}catch(Exception e){
			
		}
		for(String str:queries){
			System.out.println(main.query(str));			
		}
	}

}
posted @ 2011-06-28 00:01  ljsspace  阅读(522)  评论(0编辑  收藏  举报