单词搜索

时间:2022-07-22
本文章向大家介绍单词搜索,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

问题描述:

给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。

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

输入: 
words = ["oath","pea","eat","rain"] and board =
[
  ['o','a','a','n'],
  ['e','t','a','e'],
  ['i','h','k','r'],
  ['i','f','l','v']
]

输出: ["eat","oath"]
说明:
你可以假设所有输入都由小写字母 a-z 组成。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/word-search-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

大体思路:

​ 看到题的第一反应是使用一Set存储所有words,以board中每个点开始使用dfs遍历出所有可能的单词,然后判断是否在set中。但是这种方法最大的缺点是不知道单词的长度,因此每遍历一步都需要判断当前单词是否在set中,此外由于不知道单词长度不得不把所有的位置都遍历到。

​ 该问题可以使用前缀树结构替代hashSet,匹配到中间过程若到一个结点没匹配上,则可以直接回溯不需要再往下走了。如下图所示:不妨考虑此时刚好走过 ‘o’ ‘a’ 刚好来到下一个’a’,使用前缀树时此时可以直接回溯到上一步了,但是若时候hashSet时仍需要接着往下走。

实现代码如下:

class Solution {
    int[][] directs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
    public static class Node{
        Node[] next;
        boolean isEnd;
        public Node(){
            this.next = new Node[26];
            this.isEnd = false;
        }
    }
    Node root = null;
    char[][] board;
    boolean[][] access;
    List<String> result;
    public void createTri(String[] words){
        this.root = new Node();
        for(String word : words){
            Node cur = root;
            for(int i = 0; i < word.length(); i++){
                char c = word.charAt(i);
                if(cur.next[c - 'a'] == null){
                    cur.next[c - 'a'] = new Node();
                }
                cur = cur.next[c - 'a'];
                if(i == word.length() - 1){
                    cur.isEnd = true;
                }
            }
        }
    }
    public List<String> findWords(char[][] board, String[] words) {
        createTri(words);
        this.board = board;
        this.access = new boolean[board.length][board[0].length];
        this.result = new ArrayList<>();
        StringBuilder temp = new StringBuilder();
        for(int i = 0; i < board.length; i++){
            for(int j = 0; j < board[0].length; j++){
                dfs(i, j, root, temp);
            }
        }
        return result;
    }
    public void dfs(int i, int j, Node cur, StringBuilder temp){
        if(i < 0 || i >= board.length || j < 0 || j >= board[0].length || 
        access[i][j] || cur.next[board[i][j] - 'a'] == null){
            return;
        }
        cur = cur.next[board[i][j] - 'a'];
        access[i][j] = true;
        temp.append(board[i][j]);
        if(cur.isEnd){
            cur.isEnd = false; // 找到一个单词就删一个 防止重复
            result.add(temp.toString());
        }
        for(int[] direct : directs){
            dfs(i + direct[0], j + direct[1], cur, temp);
        }
        temp.deleteCharAt(temp.length() - 1);
        access[i][j] = false;
    }
}