面试经典150题——字典树

文章目录

  • [1、实现 Trie (前缀树)](#1、实现 Trie (前缀树))
    • [1.1 题目链接](#1.1 题目链接)
    • [1.2 题目描述](#1.2 题目描述)
    • [1.3 解题代码](#1.3 解题代码)
    • [1.4 解题思路](#1.4 解题思路)
  • [2、添加与搜索单词 - 数据结构设计](#2、添加与搜索单词 - 数据结构设计)
    • [2.1 题目链接](#2.1 题目链接)
    • [2.2 题目描述](#2.2 题目描述)
    • [2.3 解题代码](#2.3 解题代码)
    • [2.4 解题思路](#2.4 解题思路)
  • [3、单词搜索 II](#3、单词搜索 II)
    • [3.1 题目链接](#3.1 题目链接)
    • [3.2 题目描述](#3.2 题目描述)
    • [3.3 解题代码](#3.3 解题代码)
    • [3.4 解题思路](#3.4 解题思路)

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

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 解题代码

java 复制代码
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 解题代码

java 复制代码
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 解题代码

java 复制代码
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, 如果字典树中存在该字符串,将其放入数组当中,然后将字典树中的该字符串去掉。

相关推荐
Lee川7 小时前
优雅进化的JavaScript:从ES6+新特性看现代前端开发范式
javascript·面试
Lee川10 小时前
从异步迷雾到优雅流程:JavaScript异步编程与内存管理的现代化之旅
javascript·面试
晴殇i12 小时前
揭秘JavaScript中那些“不冒泡”的DOM事件
前端·javascript·面试
绝无仅有13 小时前
Redis过期删除与内存淘汰策略详解
后端·面试·架构
绝无仅有13 小时前
Redis大Key问题排查与解决方案全解析
后端·面试·架构
AAA梅狸猫14 小时前
Looper.loop() 循环机制
面试
AAA梅狸猫14 小时前
Handler基本概念
面试
Wect14 小时前
浏览器缓存机制
前端·面试·浏览器
掘金安东尼15 小时前
Fun with TypeScript Generics:玩转 TS 泛型
前端·javascript·面试
掘金安东尼15 小时前
Next.js 企业级落地
前端·javascript·面试