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