trie(前缀树)

trie(前缀树)

问题描述

给你10000个字符串集,如何快速判断一个字符串在没在这字符串集中?

解决思路

  • 如果使用最傻的遍历整个集合,时间复杂度O(n^2),显然不可行,时间复杂度太大
  • 使用trie树,它的特点是:
    • 核心思想:用空间换时间
    • 使用字符串的公共前缀,节省查找时间
    • 定义一个头节点,判断是否有走向某个节点的路,(这块的路代表的是节点的指向)

构建一棵前缀树

扩充内容

  • 我还想知道有多少字符串是以"be"开始的?
  • 某个字符串被加了多少次?

思路:

  • 给节点设置个属性,path 表示经过节点多少次,就可以判断前缀为"be"的字符串有多少个
  • 给节点一个属性,end 表示这条链被加入多少次

代码实现

package com.sparrow.zg.tree;

/**
 * 前缀树
 */
public class TrieTree {
	public static class TreeNode {
		public int path;
		public int end;
		public TreeNode[] nexts;

		public TreeNode() {
			path = 0;
			end = 0;
			nexts = new TreeNode[26];//当前节点只能接受a~b
		}
	}

	/**
	 * 前缀树:
	 * 1.查n个字符传中有多少个以**开始的
	 */
	public static class Trie {
		private TreeNode root;

		public Trie() {
			root = new TreeNode();
		}

		public void insert(String word) {
			if (word == null) {
				return;
			}
			char[] chs = word.toCharArray();
			int index = 0;
			TreeNode node = root;
			for (int i = 0; i < chs.length; i++) {
				index = chs[i] - 'a';
				if (node.nexts[index] == null) {
					node.nexts[index] = new TreeNode();
				}
				node = node.nexts[index];
				node.path++;
			}
			node.end++;
		}

		/**
		 * 查找某个字串被添加多少次
		 *
		 * @param word 查询的字串
		 * @return 被添加的次数
		 */
		public int search(String word) {
			if (word == null) {
				return 0;
			}
			char[] chs = word.toCharArray();
			TreeNode node = root;
			int index = 0;
			for (int i = 0; i < chs.length; i++) {
				index = chs[i] - 'a';
				if (node.nexts[index] == null) {
					return 0;
				}
				node = node.nexts[index];
			}
			return node.end;
		}

		/**
		 * 记录多少字符串是以word开头的
		 *
		 * @param word 前缀字符串
		 * @return 字符串的个数
		 */
		public int prefixNumber(String word) {
			if (word == null) {
				return 0;
			}
			char[] chs = word.toCharArray();
			int index = 0;
			TreeNode node = root;
			for (int i = 0; i < chs.length; i++) {
				index = chs[i] - 'a';
				if (node.nexts[index] == null) {
					return 0;
				}
				node = node.nexts[index];
			}
			return node.path;
		}

		/**
		 * 删除对应的字符串
		 *
		 * @param word 要删除的字符串
		 */
		public void delete(String word) {
			if (word == null) {
				return;
			}
			if (search(word) == 0) {
				return;
			}
			char[] chs = word.toCharArray();
			int index;
			TreeNode node = root;
			for (int i = 0; i < chs.length; i++) {
				index = chs[i] - 'a';
				if (--node.nexts[index].path == 0) {//如果当前节点指向的节点的path==0,说明下面节点只走过一次
					node.nexts[index] = null;//将下个节点的指向空
					return;
				}
				node = node.nexts[index];
			}
			node.end--;
		}
	}

参考资料

Trie(前缀树/字典树)及其应用

posted @ 2019-03-13 20:29  小小少年w  阅读(324)  评论(0)    收藏  举报