字典树(前缀树)实现

import java.util.*;


public class Solution {
      public String[] trieU (String[][] operators) {
    	ArrayList<String> ans = new ArrayList<>();
    	Trie trie = new Trie();
    	for(int i = 0; i < operators.length; ++i) {
    		if(operators[i][0].equals("1")) {
    			trie.insert(operators[i][1]);
    		} else if(operators[i][0].equals("2")) {
    			trie.delete(operators[i][1]);
    		} else if(operators[i][0].equals("3")) {
    			ans.add(trie.search(operators[i][1]) ? "YES" : "NO");
    		} else {
    			ans.add(trie.prefixNumber(operators[i][1]) + "");
    		}
    	}
	    return ans.toArray(new String[0]);
    }
    
    public static class TrieNode {
		int pass; //前缀个数
		int end; //单词个数
		TrieNode[] nexts; // 如果单词只有'a'-'z'可以用26大小的数组实现, 复杂情况使用HashMap
		TrieNode() {
			pass = end = 0;
			nexts = new TrieNode[26];
		}
	}
    
    public static class Trie {
    	TrieNode root; //空串 root.pass 表示单词总个数
    	Trie() {
    		root = new TrieNode();
    	}
    	
    	public void insert(String word) {
			if(word == null)
				return;
			char[] chs = word.toCharArray();
			TrieNode p = this.root;
			++p.pass; //单词总个数加一
			for(char ch : chs) {
				if(p.nexts[ch - 'a'] == null)
					p.nexts[ch - 'a'] = new TrieNode();
				p = p.nexts[ch - 'a'];
				++p.pass; //前缀个数加一
			}
			++p.end; //遍历到底, 单词个数加一
		}
    	
    	public void delete(String word) {
			if(search(word)) { //确保待删除单词在树中
				char[] chs = word.toCharArray();
				TrieNode p = this.root;
				--p.pass;
//				for(char ch : chs) { error
//					p = p.nexts[ch - 'a'];
//					if(--p.pass == 0) {
//						p.nexts = null;
//						return;
//					}
//				}
				for(char ch : chs) {
					if(--p.nexts[ch - 'a'].pass == 0) { //如果下一个字符的pass减为0, 即为一个单独的分支, 直接移除该分支即可, 然后return
						p.nexts[ch - 'a'] = null;
						return;
					}
					p = p.nexts[ch - 'a'];
				}
				--p.end; //如果遍历到底, 单词个数减一
			}
		}
    	
    	public boolean search(String word) {
    		if(word == null)
    			return false;
			char[] chs = word.toCharArray();
			TrieNode p = this.root;
			for(char ch : chs) {
				if(p.nexts[ch - 'a'] == null) //中途找不到某个字符, 没有这个单词
					return false;
				p = p.nexts[ch - 'a'];
			}
			//return true; //不能直接返回true 必须是单词个数
			return p.end != 0;
		}
    	
    	public int prefixNumber(String pre) {
    		if(pre == null)
    			return 0;
			char[] chs = pre.toCharArray();
			TrieNode p = this.root;
			for(char ch : chs) {
				if(p.nexts[ch - 'a'] == null) //中途找不到某个字符, 没有这个前缀
					return 0;
				p = p.nexts[ch - 'a'];
			}
			return p.pass; //遍历到底,返回前缀个数
		}
	}
}
posted @ 2022-02-10 23:04  brbrbr  阅读(50)  评论(0)    收藏  举报