212. 单词搜索 II

复制代码
https://leetcode.cn/problems/word-search-ii/description/?envType=study-plan-v2&envId=top-interview-150

思路:

  1. 我们可以先将这个单词网格转化成一颗字典树,然后再拿words进行搜索。

  2. 我们可以先将words装换成字典树,然后在在board中选点看能不能走出一条满足的路径来

对于这两个思路其实差不多,但是1的话如果board太大就很容易超时,而且无用的构建会很多(比如有一个5*5的board,理论一条路径长度应该是25,但是如果words中长的单词都只有5的话我们就根本用不到这么长)。

所以权衡来看第二种思路会更好

思路一(确实会超时):

java 复制代码
class Trie {
        Trie[] children;
        boolean isEnd;
        public Trie() {
            children = new Trie[26];
            isEnd = true; // 每个被构造出的节点都是一个单词的结尾
        }
    }
    public List<String> findWords(char[][] board, String[] words) {
        boolean[][] signed = new boolean[board.length][board[0].length];
        Trie root = new Trie();
        for(int i = 0; i < board.length; i++) {
            for(int j = 0; j < board[0].length; j++) {
                signed[i][j] = true;
                if(root.children[board[i][j] - 'a'] == null) {
                    root.children[board[i][j] - 'a'] = new Trie();
                }
                transfer(board, signed, root.children[board[i][j] - 'a'], i, j);
                signed[i][j] = false;
            }
        }
        List<String> ans = new ArrayList<>();
        for(String word : words) {
            if(search(root, word)) {
                ans.add(word);
            }
        }
        return ans;
    }
    public void transfer(char[][] board, boolean[][] signed, Trie root, int x, int y) {
        for(int i = 0; i < 4; i++) {
            int xx = x + dx[i];
            int yy = y + dy[i];
            if(xx >= 0 && xx < board.length && yy >= 0 && yy < board[0].length && !signed[xx][yy]) {
                signed[xx][yy] = true;
                if(root.children[board[xx][yy] - 'a'] == null) root.children[board[xx][yy] - 'a'] = new Trie();
                transfer(board, signed, root.children[board[xx][yy] - 'a'], xx, yy);
                signed[xx][yy] = false;
            }
        }
    }

思路二:

java 复制代码
    class Trie {
        Trie[] children;
        String word; // 如果当前节点是不是一个单词的结尾,那么word=这个单词,否则word=""
        public Trie() {
            children = new Trie[26];
            word = "";
        }
    }
    public List<String> findWords(char[][] board, String[] words) {
        // 将words构建成字典树
        Trie root = new Trie();
        for(String word : words) {
            add(root, word);
        }
        boolean[][] signed = new boolean[board.length][board[0].length];
        HashSet<String> ans = new HashSet<>();
        // 在board中选取点在Tire中走看是否存在路径
        for(int i = 0; i < board.length; i++) {
            for(int j = 0; j < board[0].length; j++) {
                signed[i][j] = true;
                dfs(root, board, signed, ans, i, j);
                signed[i][j] = false;
            }
        }
        return new ArrayList<>(ans);
    }
    
    public void add(Trie root, String word) {
        for(int i = 0; i < word.length(); i++) {
            if(root.children[word.charAt(i) - 'a'] == null) {
                root.children[word.charAt(i) - 'a'] = new Trie();
            }
            root = root.children[word.charAt(i) - 'a'];
        }
        root.word = word;
    }

    /**
     * 深度优先搜索
     * @param root 当前节点
     * @param board 单词网格
     * @param signed 标记数组
     * @param ans 答案
     * @param x 当前位置x坐标
     * @param y 当前位置y坐标
     */
    public void dfs(Trie root, char[][] board, boolean[][] signed, HashSet<String> ans, int x, int y) {
        if(root == null) return;
        if(!Objects.equals(root.word, "")) {
            ans.add(root.word);
        }
        root = root.children[board[x][y] - 'a'];
        for(int i = 0; i < 4; i++) {
            int xx = x + dx[i];
            int yy = y + dy[i];
            if(xx >= 0 && xx < board.length && yy >= 0 && yy < board[0].length && !signed[xx][yy]) {
                char ch = board[xx][yy];
                signed[xx][yy] = true;
                dfs(root, board, signed, ans, xx, yy);
                signed[xx][yy] = false;
            }
        }
        if (root != null && root.word != "") ans.add(root.word);
    }

    public boolean search(Trie root, String word) {
        for(int i = 0; i < word.length(); i++) {
            if(root.children[word.charAt(i) - 'a'] == null) {
                return false;
            }
            root = root.children[word.charAt(i) - 'a'];
        }
        return "".equals(root.word);
    }
相关推荐
JAVA面经实录91719 小时前
Java企业级工程化·终极完整版背诵手册(无遗漏、全覆盖、面试+落地通用)
java·开发语言·面试
王老师青少年编程20 小时前
csp信奥赛C++高频考点专项训练之贪心算法 --【哈夫曼贪心】:合并果子
c++·算法·贪心·csp·信奥赛·哈夫曼贪心·合并果子
叼烟扛炮20 小时前
C++第二讲:类和对象(上)
数据结构·c++·算法·类和对象·struct·实例化
天疆说21 小时前
【哈密顿力学】深入解读航天器交会最优控制中的Hamilton函数
人工智能·算法·机器学习
许彰午21 小时前
CacheSQL(二):主从复制——OpLog 环形缓冲区与故障自动恢复
java·数据库·缓存
wuweijianlove21 小时前
关于算法设计中的代价函数优化与约束求解的技术7
算法
leoufung1 天前
LeetCode 149: Max Points on a Line - 解题思路详解
算法·leetcode·职场和发展
样例过了就是过了1 天前
LeetCode热题100 最长公共子序列
c++·算法·leetcode·动态规划
HXDGCL1 天前
矩形环形导轨:自动化循环线的核心运动单元解析
运维·算法·自动化
Bat U1 天前
JavaEE|多线程初阶(七)
java·开发语言