Bootstrap

面试经典150题——字典树


对于字典树而言,之前做过类似的教程,详情可以看走入字典树一

1、实现 Trie (前缀树)

1.1 题目链接

点击跳转到题目位置

1.2 题目描述

Trie(发音类似 “try”)或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补全和拼写检查。

请你实现 Trie 类:

  • Trie() 初始化前缀树对象。
  • void insert(String word) 向前缀树中插入字符串 word 。
  • boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false 。
  • boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false 。

提示:

  • 1 <= word.length, prefix.length <= 2000
  • word 和 prefix 仅由小写英文字母组成
  • insert、search 和 startsWith 调用次数 总计 不超过 3 * 104

1.3 解题代码


class TrieNode{
    TrieNode[] next;
    boolean end;
    TrieNode(){
        next = new TrieNode[26];
        end = false;
    }
}


class Trie {

    TrieNode root;

    public Trie() {
        root = new TrieNode();
    }
    
    public void insert(String word) {
        TrieNode now = root;
        for(int i = 0; i < word.length(); ++i){
            int child = word.charAt(i) - 'a';
            if(now.next[child] == null){
                now.next[child] = new TrieNode();
            }
            now = now.next[child];
        }
        now.end = true;
    }
    
    public boolean search(String word) {
        TrieNode now = root;
        for(int i = 0; i < word.length(); ++i){
            int child = word.charAt(i) - 'a';
            if(now.next[child] == null){
                return false;
            }
            now = now.next[child]; 
        }
        return now.end;
    }
    
    public boolean startsWith(String prefix) {
        TrieNode now = root;
        for(int i = 0; i < prefix.length(); ++i){
            int child = prefix.charAt(i) - 'a';
            if(now.next[child] == null){
                return false;
            }
            now = now.next[child]; 
        }
        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);
 */

1.4 解题思路

  1. 字典树经典题型,套用模板即可。

2、添加与搜索单词 - 数据结构设计

2.1 题目链接

点击跳转到题目位置

2.2 题目描述

请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。

实现词典类 WordDictionary :

  • WordDictionary() 初始化词典对象
  • void addWord(word) 将 word 添加到数据结构中,之后可以对它进行匹配
  • bool search(word) 如果数据结构中存在字符串与 word 匹配,则返回 true ;否则,返回 false 。word 中可能包含一些 ‘.’ ,每个 . 都可以表示任何一个字母。

提示:

  • 1 <= word.length <= 25
  • addWord 中的 word 由小写英文字母组成
  • search 中的 word 由 ‘.’ 或小写英文字母组成
  • 最多调用 104 次 addWord 和 search

2.3 解题代码

class TrieNode{
    TrieNode[] next;
    boolean end;
    TrieNode(){
        next = new TrieNode[26];
        end = false;
    }
}

class WordDictionary {
    TrieNode root;
    public WordDictionary() {
        root = new TrieNode();
    }
    
    public void addWord(String word) {
        TrieNode now = root;
        for(int i = 0; i < word.length(); ++i){
            int child = word.charAt(i) - 'a';
            if(now.next[child] == null){
                now.next[child] = new TrieNode();
            }
            now = now.next[child];    
        }
        now.end = true;
    }
    
    public boolean search(String word) {
        Queue<TrieNode> q = new LinkedList<>();
        q.offer(root);
        for(int i = 0; i < word.length(); ++i){
            int len = q.size();
            for(int j = 0; j < len; ++j){ 
                TrieNode x = q.peek();
                q.poll();
                if(word.charAt(i) == '.'){
                    for(int k = 0; k < 26; ++k){
                        if(x.next[k] != null){
                            q.offer(x.next[k]);
                        }
                    }
                } else{
                    int child = word.charAt(i) - 'a';
                    if(x.next[child] != null){
                        q.offer(x.next[child]);
                    }
                } 
            }
            if(q.size() == 0){
                return false;
            }
        }
        while(!q.isEmpty()){
            TrieNode x = q.peek();
            if(x.end == true){
                return true;
            }
            q.poll();
        }
        return false;
    }
}

/**
 * Your WordDictionary object will be instantiated and called as such:
 * WordDictionary obj = new WordDictionary();
 * obj.addWord(word);
 * boolean param_2 = obj.search(word);
 */

2.4 解题思路

  1. 套用字典树模板。
  2. 对于搜索,因为癞子的存在,所以需要使用广度优先搜索

3、单词搜索 II

3.1 题目链接

点击跳转到题目位置

3.2 题目描述

给定一个 m x n 二维字符网格 board 和一个单词(字符串)列表 words, 返回所有二维网格上的单词 。

单词必须按照字母顺序,通过 相邻的单元格 内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。

3.3 解题代码

class Solution {
    int[][] dir = {
        {-1, 0},
        {1, 0},
        {0, 1},
        {0, -1},
    };
    Trie trie = new Trie();
    List<String> res = new ArrayList<>();

    public void dfs(TrieNode root, int x, int y, int m, int n, char[][] board, int vis[][], StringBuffer sb){        
        if(root.end == true){
            String str = sb.toString();
            res.add(str);
            root.end = false;
        }
        for(int i = 0; i < 4; ++i){
            int tx = x + dir[i][0];
            int ty = y + dir[i][1];
            if(tx < 0 || tx >= m || ty < 0 || ty >= n || vis[tx][ty] == 1){
                continue;
            }
            if(root.next[board[tx][ty] - 'a'] != null){
                vis[tx][ty] = 1;
                sb.append(board[tx][ty]);
                dfs(root.next[board[tx][ty] - 'a'], tx, ty, m, n, board, vis, sb);
                sb.deleteCharAt(sb.length() - 1);
                vis[tx][ty] = 0;
            }
        }
    } 

    public List<String> findWords(char[][] board, String[] words) {
        int m = board.length;
        int n = board[0].length;
        int[][] vis = new int[m][n];
        for(int i = 0; i < words.length; ++i){
            trie.insert(words[i]);
        }
        StringBuffer sb = new StringBuffer();
        Queue<Character> q = new LinkedList<>();
        
        for(int i = 0; i < m; ++i){
            for(int j = 0; j < n; ++j){
                if(trie.root.next[board[i][j] - 'a'] != null){
                    vis[i][j] = 1;
                    sb.append(board[i][j]);
                    dfs(trie.root.next[board[i][j] - 'a'], i, j, m, n, board, vis, sb);
                    sb.deleteCharAt(sb.length() - 1);
                    vis[i][j] = 0;
                }             
            }
        }
        return res;
    }
}

class TrieNode{
    TrieNode[] next;
    boolean end;
    TrieNode(){
        next = new TrieNode[26];
        end = false;
    }
}

class Trie {
    TrieNode root;

    public Trie() {
        root = new TrieNode();
    }
    
    public void insert(String word) {
        TrieNode now = root;
        for(int i = 0; i < word.length(); ++i){
            int child = word.charAt(i) - 'a';
            if(now.next[child] == null){
                now.next[child] = new TrieNode();
            }
            now = now.next[child];
        }
        now.end = true;
    }
    
    public boolean search(String word) {
        TrieNode now = root;
        for(int i = 0; i < word.length(); ++i){
            int child = word.charAt(i) - 'a';
            if(now.next[child] == null){
                return false;
            }
            now = now.next[child]; 
        }
        return now.end;
    }
    
    public boolean startsWith(String prefix) {
        TrieNode now = root;
        for(int i = 0; i < prefix.length(); ++i){
            int child = prefix.charAt(i) - 'a';
            if(now.next[child] == null){
                return false;
            }
            now = now.next[child]; 
        }
        return true;
    }
}

3.4 解题思路

1, 字典树+回溯思路
2, 如果字典树中存在该字符串,将其放入数组当中,然后将字典树中的该字符串去掉。

;