前缀树的实现,从一道较为简单的题来理解


X星球的身份证是一个18位的字符串,每位只包含0~9,上面包含了个人信息。并且根据2个人的身份证可以知道2个人的相似度。相似度:2个人身份证的最长公共前缀的长度。假如A和B的相似度为k,那么A和B的身份证的前面k位相同的,并且第k+1位一定不同。没有两个人的身份证是完全相同的。现在有一个身份证库,保存有n人的身份证帐号。有Q个询问。每个询问给出一个人的身份证,询问身份证库的人和这个人最大的相似度,并且询问身份证库有多少个人和他的相似度等于这个最大相似度。


示例输入: (第一行为n,Q,接下来是n个人的身份证号,和Q个查询身份证号)
3 2
333333333333333333
111111122222222222
111111133333333333
111111111000000000
000000000000000000


示例输出:(每个查询Q对应一个最大公共前缀长度(7),以及该身份证库中有多少个人是和该查询有最大公共前缀(2))
7 2
0 3


import java.util.Scanner;

//前缀树的树节点
class TreeNode{
public int path;
public int end;
public TreeNode[] next;

public TreeNode(){
path = 0;//有多少路径(字符串)经过该节点
end = 0;//有多少路径(字符串)以该节点为终点
next = new TreeNode[10];//10个字符(0-9)//该节点是否为终点
}
}


//前缀树
class TrieTree{
public TreeNode root;
public TrieTree(){
root = new TreeNode();
}

public void insert(String str){ //关键在于插入,插入时,在从父节点到子节点的路径上存储一个元素
if(str == null || str.length() == 0) {
return ;
}

int len = str.length();
TreeNode curNode = root;
for(int i=0; i<len; i++){
char tmp = str.charAt(i);
int index = (int)tmp - '0';
if(curNode.next[index] == null){
curNode.next[index] = new TreeNode();
}
curNode.path++;
curNode = curNode.next[index];
}
curNode.path++;
curNode.end++;
}

public int size(){
return root.path;
}

public int count(String str){
if(str == null || str.length() == 0){
return 0;
}
int len = str.length();
TreeNode curNode = root;
for(int i=0; i<len; i++){
char tmp = str.charAt(i);
int index = (int) tmp - '0';
if(curNode.next[index] == null){
return 0;
}
curNode = curNode.next[index];
}
return curNode.end;
}

public int countPrefix(String str){
if(str == null || str.length() == 0) return 0;
int len = str.length();
TreeNode curNode = root;
for(int i=0; i<len; i++){
char tmp = str.charAt(i);
int index = (int) tmp - '0';
if(curNode.next[index] == null){
return 0;
}
curNode = curNode.next[index];
}
return curNode.path;
}

public int maxPrefixLen(String str){
if(str == null || str.length() == 0) return 0;
int len = str.length();
TreeNode curNode = root;
for(int i=0; i<len; i++){
char tmp = str.charAt(i);
int index = (int) tmp - '0';
if(curNode.next[index] == null){
return i;
}
curNode = curNode.next[index];
}
return len;
}

public int countMaxPrefix(String str){
if(str == null || str.length() == 0) return 0;
int len = str.length();
TreeNode curNode = root;
for(int i=0; i<len; i++){
char tmp = str.charAt(i);
int index = (int) tmp - '0';
if(curNode.next[index] == null){
break;
}
curNode = curNode.next[index];
}
return curNode.path;
}
}

//主函数
public class Main{
public static void main(String[] args) {
TrieTree tree = new TrieTree();
Scanner s = new Scanner(System.in);
int n = s.nextInt();
int q = s.nextInt();
while(n>0){
n--;
tree.insert(s.next());
}

String[] qs = new String[q];
for(int i=0; i<q; i++){
qs[i] = s.next();
}
for(String str : qs){
System.out.println(tree.maxPrefixLen(str) + " " + tree.countMaxPrefix(str));
}
//test
//tree.insert("333333333333333333");
//tree.insert("111111122222222222");
//tree.insert("111111133333333333");
//
//System.out.println(tree.maxPrefixLen("111111111000000000"));
//System.out.println(tree.maxPrefixLen("000000000000000000"));
//7
//0
}

}