字典树(前缀树)--java

前缀树

从一道较为简单的题来理解


> **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
	}
	
}

Reference:
https://blog.csdn.net/xushiyu1996818/article/details/89354425

第2题:添加与搜索单词

添加与搜索单词 - 数据结构设计
前缀树的边代表一个元素

class WordDictionary {
    
    Tree root;
    /** Initialize your data structure here. */
    public WordDictionary() {
        root = new Tree();
    }
    
    public void addWord(String word) {
        Tree head = root;
        for(char c : word.toCharArray()){
            int t = c - 'a';
            if(head.nums[t] == null){
                head.nums[t] = new Tree();
            }
            head = head.nums[t];
        }
        head.isOver = true;
    }
    
    public boolean search(String word) {
        Tree head = root;
        return dfs(word, 0, head);
    }

    private boolean dfs(String word, int index, Tree head){
        if(index == word.length()){
            if(head.isOver) return true;
            return false;
        }
        char c = word.charAt(index);
        if( c == '.' ){
            for(int i=0; i<26; i++){
                if(head.nums[i] != null){
                    if(dfs(word, index+1, head.nums[i])){
                        return true;
                    }
                }
            }
        }else{
            int t = c - 'a';
            if(head.nums[t] != null){
                if(dfs(word, index+1, head.nums[t])){
                    return true;
                }
            }
        }
        return false;
    }
}

class Tree{
    Tree [] nums;
    boolean isOver = false;
    
    public Tree(){
        nums = new Tree[26];
    }
}

第3题:实现Trie(前缀树)

leetcode208. 实现Trie(前缀树)

class Trie {
    private Node root;

    public Trie() {
        root = new Node();
    }
    
    public void insert(String word) {
        Node node = root;
        for(int i=0; i<word.length(); i++){
            char curC = word.charAt(i);
            if( !node.containsKey(curC)){
                node.put(curC, new Node());
            }
            node = node.get(curC);
        }
        node.setEnd();
    }
    
    public boolean search(String word) {
        Node node = searchPrefix(word);
        return node != null && node.isEnd();
    }
    
    public boolean startsWith(String prefix) {
        Node node = searchPrefix(prefix);
        return node != null;
    }

    private Node searchPrefix(String word){
        Node node = root;
        for(int i=0; i<word.length(); i++){
            char c = word.charAt(i);
            if(node.containsKey(c)){
                node = node.get(c);
            }else{
                return null;
            }
        }
        return node;
    }
}

class Node{
    private Node[] links;
    private final int R = 26;
    private boolean end;

    public Node(){
        links = new Node[R];
    }

    public boolean containsKey(char c){
        return links[c - 'a'] != null;
    }

    public Node get(char c){
        return links[c-'a'];
    }

    public void put(char c, Node node){
        links[c-'a'] = node;
    }

    public void setEnd(){
        end = true;
    }

    public boolean isEnd(){
        return end;
    }
}

/**
 * Your Trie object will be instantiated and called as such:
 * Trie obj = new Trie();
 * obj.insert(word);
 * boolean param_2 = obj.search(word);
 * boolean param_3 = obj.startsWith(prefix);
 */
原文地址:https://www.cnblogs.com/bacmive/p/15063384.html