# Trie

## 1、实现 Trie (前缀树)

### 1）题目要求

Trie trie = new Trie();

trie.insert(“apple”);
trie.search(“apple”); // 返回 true
trie.search(“app”); // 返回 false
trie.startsWith(“app”); // 返回 true
trie.insert(“app”);
trie.search(“app”); // 返回 true

### 2）我的解法

class Trie {
class TrieNode{
public boolean is_end;
public TrieNode[] next;
TrieNode(){
is_end=false;
next=new TrieNode[26];
}
}
TrieNode root;
/** Initialize your data structure here. */
public Trie() {
root=new TrieNode();
}

/** Inserts a word into the trie. */
public void insert(String word) {
TrieNode cur=root;
for(int i=0;i<word.length();i++){
if(cur.next[word.charAt(i)-'a']==null)cur.next[word.charAt(i)-'a']=new TrieNode();
cur=cur.next[word.charAt(i)-'a'];
}
cur.is_end=true;//最后一个字母之后那个结点设为结束，而不是最后一个字母设为结束
}

/** Returns if the word is in the trie. */
public boolean search(String word) {
TrieNode cur=root;
for(int i=0;i<word.length();i++){
if(cur.next[word.charAt(i)-'a']!=null)cur=cur.next[word.charAt(i)-'a'];
else return false;
}
if(!cur.is_end)return false;
return true;
}

/** Returns if there is any word in the trie that starts with the given prefix. */
public boolean startsWith(String prefix) {
TrieNode cur=root;
for(int i=0;i<prefix.length();i++){
if(cur.next[prefix.charAt(i)-'a']!=null)cur=cur.next[prefix.charAt(i)-'a'];
else return false;
}
return true;
}
}

/**
* 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);
*/


### 3）其他解法

public class Trie {
private boolean is_string=false;
private Trie next[]=new Trie[26];

public Trie(){}

public void insert(String word){//插入单词
Trie root=this;
char w[]=word.toCharArray();
for(int i=0;i<w.length;++i){
if(root.next[w[i]-'a']==null)root.next[w[i]-'a']=new Trie();
root=root.next[w[i]-'a'];
}
root.is_string=true;
}

public boolean search(String word){//查找单词
Trie root=this;
char w[]=word.toCharArray();
for(int i=0;i<w.length;++i){
if(root.next[w[i]-'a']==null)return false;
root=root.next[w[i]-'a'];
}
return root.is_string;
}

public boolean startsWith(String prefix){//查找前缀
Trie root=this;
char p[]=prefix.toCharArray();
for(int i=0;i<p.length;++i){
if(root.next[p[i]-'a']==null)return false;
root=root.next[p[i]-'a'];
}
return true;
}
}


### 4）自己的优化代码

class Trie {
class TrieNode{
public boolean is_end;
public TrieNode[] next;
TrieNode(){
is_end=false;
next=new TrieNode[26];
}
}
TrieNode root;
/** Initialize your data structure here. */
public Trie() {
root=new TrieNode();
}

/** Inserts a word into the trie. */
public void insert(String word) {
TrieNode cur=root;
for(int i=0;i<word.length();i++){
if(cur.next[word.charAt(i)-'a']==null)cur.next[word.charAt(i)-'a']=new TrieNode();
cur=cur.next[word.charAt(i)-'a'];
}
cur.is_end=true;//最后一个字母之后那个结点设为结束，而不是最后一个字母设为结束
}

/** Returns if the word is in the trie. */
public boolean search(String word) {
TrieNode cur=root;
for(int i=0;i<word.length();i++){
if(cur.next[word.charAt(i)-'a']!=null)cur=cur.next[word.charAt(i)-'a'];
else return false;
}
if(!cur.is_end)return false;
return true;
}

/** Returns if there is any word in the trie that starts with the given prefix. */
public boolean startsWith(String prefix) {
TrieNode cur=root;
for(int i=0;i<prefix.length();i++){
if(cur.next[prefix.charAt(i)-'a']!=null)cur=cur.next[prefix.charAt(i)-'a'];
else return false;
}
return true;
}
}

/**
* 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);
*/


## 2、 键值映射（677、Medium）

### 2）我的解法

class MapSum {
class Trie{
boolean is_end=false;
int val=0;
Trie[] next=new Trie[26];
public Trie(){}
}
Trie root;
/** Initialize your data structure here. */
public MapSum() {
root=new Trie();
}

public void insert(String key, int val) {
Trie cur=root;
for(int i=0;i<key.length();i++){
cur.val+=val;
if(cur.next[key.charAt(i)-'a']==null)cur.next[key.charAt(i)-'a']=new Trie();
cur=cur.next[key.charAt(i)-'a'];
}
cur.val+=val;
if(cur.is_end){//当完全重复了时，进行覆盖
cur=root;
for(int i=0;i<key.length();i++){
cur.val=val;
cur=cur.next[key.charAt(i)-'a'];
}
cur.val=val;
}
cur.is_end=true;
}

public int sum(String prefix) {
Trie cur=root;
for(int i=0;i<prefix.length();i++){
if(cur.next[prefix.charAt(i)-'a']==null)return 0;
cur=cur.next[prefix.charAt(i)-'a'];
}
return cur.val;
}
}



### 3）其他解法

class MapSum {
private:
bool isEnd; // 是否为最后一个字母
MapSum* next[26]; // 字母表
int value; // 若为最后一个字母，其对应的值

// 深度优先遍历算法
int dfs(MapSum* root) {
if(!root) return 0; // 递归基：如果当前访问的MapSum为空，则直接返回0

int res = 0;
if(root->isEnd) res += root->value; // 若当前节点不为空且isEnd，则加上其值
for(MapSum* cur : root->next) { // 再遍历当前节点的next数组中所有的MapSum
res += dfs(cur);
}

return res;
}
public:
/** Initialize your data structure here. */
MapSum() {
isEnd = false;
memset(next, 0, sizeof(next));
value = 0;
}

void insert(string key, int val) {
MapSum* node = this;
for(char ch : key) {
if(node->next[ch - 'a'] == NULL) {
node->next[ch - 'a'] = new MapSum();
}
node = node->next[ch - 'a'];
}
node->isEnd = true;
node->value = val; // 相比较正常的前缀树，只是新增了一个value属性
}

int sum(string prefix) {
MapSum* node = this;
for(char ch : prefix) {
if(node->next[ch - 'a'] == NULL) return 0;
node = node->next[ch - 'a'];
}
return dfs(node);
}
};



### 4）自己的优化代码

class MapSum {
class Trie{
boolean is_end=false;
int val=0;
Trie[] next=new Trie[26];
public Trie(){}
}
Trie root;
/** Initialize your data structure here. */
public MapSum() {
root=new Trie();
}

public void insert(String key, int val) {
Trie cur=root;
for(int i=0;i<key.length();i++){
cur.val+=val;
if(cur.next[key.charAt(i)-'a']==null)cur.next[key.charAt(i)-'a']=new Trie();
cur=cur.next[key.charAt(i)-'a'];
}
cur.val+=val;
if(cur.is_end){//当完全重复了时，进行覆盖
cur=root;
for(int i=0;i<key.length();i++){
cur.val=val;
cur=cur.next[key.charAt(i)-'a'];
}
cur.val=val;
}
cur.is_end=true;
}

public int sum(String prefix) {
Trie cur=root;
for(int i=0;i<prefix.length();i++){
if(cur.next[prefix.charAt(i)-'a']==null)return 0;
cur=cur.next[prefix.charAt(i)-'a'];
}
return cur.val;
}
}



## 3、单词搜索 II（212、Hard）

### 1）题目要求

words = [“oath”,“pea”,“eat”,“rain”] and board =
[
[‘o’,‘a’,‘a’,‘n’],
[‘e’,‘t’,‘a’,‘e’],
[‘i’,‘h’,‘k’,‘r’],
[‘i’,‘f’,‘l’,‘v’]
]

### 2）我的解法

class TrieNode{
public boolean is_end;
public TrieNode[] next;
public boolean tag;//判断该路径是否被访问过，search到达一次后置为true
TrieNode(){
is_end=false;
next=new TrieNode[26];
tag=false;
}
}
class Trie {
TrieNode root;
/** Initialize your data structure here. */
public Trie() {
root=new TrieNode();
}

/** Inserts a word into the trie. */
public void insert(String word) {
TrieNode cur=root;
for(int i=0;i<word.length();i++){
if(cur.next[word.charAt(i)-'a']==null)cur.next[word.charAt(i)-'a']=new TrieNode();
cur=cur.next[word.charAt(i)-'a'];
}
cur.is_end=true;//最后一个字母之后那个结点设为结束，而不是最后一个字母设为结束
}

/** Returns if the word is in the trie. */
public boolean search(String word) {
TrieNode cur=root;
for(int i=0;i<word.length();i++){
if(cur.next[word.charAt(i)-'a']!=null)cur=cur.next[word.charAt(i)-'a'];
else return false;
}
if(!cur.is_end)return false;
//如果被访问过，返回false
if(cur.tag)return false;
cur.tag=true;
//标记为被访问过
return true;
}

/** Returns if there is any word in the trie that starts with the given prefix. */
public boolean startsWith(String prefix) {
TrieNode cur=root;
for(int i=0;i<prefix.length();i++){
if(cur.next[prefix.charAt(i)-'a']!=null)cur=cur.next[prefix.charAt(i)-'a'];
else return false;
}
return true;
}
}
class Solution {
Trie t;
List<String> result=new ArrayList<>();
boolean[][] vi;
StringBuilder s=new StringBuilder();
public void backpack(int i,int j,char[][] board){
if(i<0||j<0||i>=board.length||j>=board[0].length||vi[i][j])return ;
s.append(board[i][j]);
vi[i][j]=true;
if(!t.startsWith(s.toString())){
vi[i][j]=false;
s.deleteCharAt(s.length()-1);
return ;
}
if(t.search(s.toString())){

}
backpack(i-1,j,board);

backpack(i+1,j,board);

backpack(i,j-1,board);

backpack(i,j+1,board);

vi[i][j]=false;
s.deleteCharAt(s.length()-1);
}
public List<String> findWords(char[][] board, String[] words) {
t=new Trie();
for(int i=0;i<words.length;i++){
t.insert(words[i]);
}
vi=new boolean[board.length][board[0].length];
for(int i=0;i<board.length;i++){
for(int j=0;j<board[0].length;j++){
backpack(i,j,board);
}
}
result.sort((o1,o2)->o1.compareTo(o2));
return result;

}
}


### 3）其他解法

import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class findWords_212 {
public List<String> findWords(char[][] board, String[] words) {
//构建字典树
wordTrie myTrie=new wordTrie();
trieNode root=myTrie.root;
for(String s:words)
myTrie.insert(s);

//使用set防止重复
Set<String> result =new HashSet<>();
int m=board.length;
int n=board[0].length;
boolean [][]visited=new boolean[m][n];
//遍历整个二维数组
for(int i=0;i<board.length; i++){
for (int j = 0; j < board [0].length; j++){
find(board,visited,i,j,m,n,result,root);
}
}
System.out.print(result);
}
private void find(char [] [] board, boolean [][]visited,int i,int j,int m,int n,Set<String> result,trieNode cur){
//边界以及是否已经访问判断
if(i<0||i>=m||j<0||j>=n||visited[i][j])
return;
cur=cur.child[board[i][j]-'a'];
visited[i][j]=true;
if(cur==null)
{
//如果单词不匹配，回退
visited[i][j]=false;
return;
}
//找到单词加入
if(cur.isLeaf)
{
//            visited[i][j]=false;
//            return;
}
find(board,visited,i+1,j,m,n,result,cur);
find(board,visited,i,j+1,m,n,result,cur);
find(board,visited,i,j-1,m,n,result,cur);
find(board,visited,i-1,j,m,n,result,cur);
//最后要回退，因为下一个起点可能会用到上一个起点的字符
visited[i][j]=false;
}

}

//字典树
class wordTrie{
public trieNode root=new trieNode();
public void insert(String s){
trieNode cur=root;
for(char c:s.toCharArray()){
if(cur.child[c-'a']==null){
cur.child [c-'a'] = new trieNode();
cur=cur.child[c-'a'];
}else
cur=cur.child [c-'a'];
}
cur.isLeaf=true;
cur.val=s;
}
}
//字典树结点
class trieNode{
public String val;
public trieNode[] child=new trieNode[26];
public boolean isLeaf=false;

trieNode(){

}
}



### 4）自己的优化代码

1、每次递归带上一个TrieNode cur，避免每次都重新遍历

class TrieNode{
public boolean is_end;
public TrieNode[] next;
public boolean tag;//判断该路径是否被访问过，search到达一次后置为true
TrieNode(){
is_end=false;
next=new TrieNode[26];
tag=false;
}
}
class Trie {
TrieNode root;
/** Initialize your data structure here. */
public Trie() {
root=new TrieNode();
}

/** Inserts a word into the trie. */
public void insert(String word) {
TrieNode cur=root;
for(int i=0;i<word.length();i++){
if(cur.next[word.charAt(i)-'a']==null)cur.next[word.charAt(i)-'a']=new TrieNode();
cur=cur.next[word.charAt(i)-'a'];
}
cur.is_end=true;//最后一个字母之后那个结点设为结束，而不是最后一个字母设为结束
}
}
class Solution {
Trie t;
List<String> result=new ArrayList<>();
boolean[][] vi;
StringBuilder s=new StringBuilder();
public void backpack(int i,int j,char[][] board,TrieNode cur){
if(i<0||j<0||i>=board.length||j>=board[0].length||vi[i][j])return ;
if(cur.next[board[i][j]-'a']==null)return;//相当于startwith
cur=cur.next[board[i][j]-'a'];
s.append(board[i][j]);
vi[i][j]=true;
if(cur.is_end&&!cur.tag){//相当于search
cur.tag=true;

}
backpack(i-1,j,board,cur);

backpack(i+1,j,board,cur);

backpack(i,j-1,board,cur);

backpack(i,j+1,board,cur);

vi[i][j]=false;
s.deleteCharAt(s.length()-1);
}
public List<String> findWords(char[][] board, String[] words) {
t=new Trie();
for(int i=0;i<words.length;i++){
t.insert(words[i]);
}
vi=new boolean[board.length][board[0].length];
for(int i=0;i<board.length;i++){
for(int j=0;j<board[0].length;j++){
backpack(i,j,board,t.root);
}
}
result.sort((o1,o2)->o1.compareTo(o2));
return result;

}
}


2、直接每个结点记录字符串，省去append时间

class TrieNode{
public boolean is_end;
public TrieNode[] next;
public boolean tag;//判断该路径是否被访问过，search到达一次后置为true
public String val;
TrieNode(){
is_end=false;
next=new TrieNode[26];
tag=false;
}
}
class Trie {
TrieNode root;
/** Initialize your data structure here. */
public Trie() {
root=new TrieNode();
}

/** Inserts a word into the trie. */
public void insert(String word) {
TrieNode cur=root;
for(int i=0;i<word.length();i++){
if(cur.next[word.charAt(i)-'a']==null)cur.next[word.charAt(i)-'a']=new TrieNode();
cur=cur.next[word.charAt(i)-'a'];
}
cur.is_end=true;//最后一个字母之后那个结点设为结束，而不是最后一个字母设为结束
cur.val=word;
}

}
class Solution {
Trie t;
List<String> result=new ArrayList<>();
boolean[][] vi;
StringBuilder s=new StringBuilder();
public void backpack(int i,int j,char[][] board,TrieNode cur){
if(i<0||j<0||i>=board.length||j>=board[0].length||vi[i][j])return ;
if(cur.next[board[i][j]-'a']==null)return;//相当于startwith
cur=cur.next[board[i][j]-'a'];

vi[i][j]=true;
if(cur.is_end&&!cur.tag){//相当于search
cur.tag=true;

}
backpack(i-1,j,board,cur);

backpack(i+1,j,board,cur);

backpack(i,j-1,board,cur);

backpack(i,j+1,board,cur);

vi[i][j]=false;
}
public List<String> findWords(char[][] board, String[] words) {
t=new Trie();
for(int i=0;i<words.length;i++){
t.insert(words[i]);
}
vi=new boolean[board.length][board[0].length];
for(int i=0;i<board.length;i++){
for(int j=0;j<board[0].length;j++){
backpack(i,j,board,t.root);
}
}
result.sort((o1,o2)->o1.compareTo(o2));
return result;

}
}


### 5）学到的东西

• 点赞
• 评论
• 分享
x

海报分享

扫一扫，分享海报

• 收藏
• 手机看

分享到微信朋友圈

x

扫一扫，手机阅读

• 打赏

打赏

波仔头

你的鼓励将是我创作的最大动力

C币 余额
2C币 4C币 6C币 10C币 20C币 50C币
• 一键三连

点赞Mark关注该博主, 随时了解TA的最新博文
11-11 45

06-16 2万+
04-11 164
07-22 57
04-20 227