LeetCode 高级 - 单词搜索 II

单词搜索 II

给定一个二维网格 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 组成。

提示:

  • 你需要优化回溯算法以通过更大数据量的测试。你能否早点停止回溯?
  • 如果当前单词不存在于所有单词的前缀中,则可以立即停止回溯。什么样的数据结构可以有效地执行这样的操作?散列表是否可行?为什么? 前缀树如何?如果你想学习如何实现一个基本的前缀树,请先查看这个问题: 实现Trie(前缀树)

分析

核心思想:DFS + 前缀树

关于提示中提到的 实现Trie(前缀树) 一题,解法见 LeetCode 高级 - 实现 Trie(前缀树)

本题的提示很明确,就是在引导我们使用前缀树匹配,减少回溯规模,以通过大数据量的测试。(貌似不采取前缀树,直接常规 DFS 会 TLE)

至于 DFS,套路很清晰,见代码即可。

代码

class Solution {
    private TrieNode root = new TrieNode();
    private int[] row = new int[]{-1,1,0,0};
    private int[] col = new int[]{0,0,-1,1};

    public List<String> findWords(char[][] board, String[] words) {

        //直接用 list 存,会出现 重复记录word 的情况。。。汗颜!
        //List<String> results = new ArrayList<String>();

        //改用 HashSet 暂存结果,确保不会出现重复word
        HashSet<String> temp = new HashSet<>();

        //前缀树
        for(int i=0;i<words.length;i++){
            TrieNode node = root;
            for(int j=0;j<words[i].length();j++)
                node = node.add(words[i].charAt(j));
            node.word = words[i];
        }
        //DFS
        boolean[][] visited = new boolean[board.length][board[0].length];
        for(int i=0;i<board.length;i++){
            for(int j=0;j<board[0].length;j++){
                if(root.ifExists(board[i][j])){
                    find(board,visited,i,j,root,temp);
                }
            }
        }

        List<String> results = new ArrayList<String>();
        results.addAll(temp);
        return results;
    }

    private void find(char[][] board,boolean[][] visited,int x,int y,TrieNode node,HashSet<String> temp){
        visited[x][y]=true;
        TrieNode cur = node.next[board[x][y]-'a'];
        //到达可匹配子串,记录当前 word
        if(cur.word!=null)
            temp.add(cur.word);
        for(int i=0;i<4;i++){
            int x2 = x + row[i];
            int y2 = y + col[i];
            if(x2>=0 && x2<board.length && y2 >=0 && y2 < board[0].length && !visited[x2][y2] ){
                if(cur.ifExists(board[x2][y2])){
                    find(board,visited,x2,y2,cur,temp);
                }
            }
        }
        visited[x][y] = false;
    }
    //前缀树
    class TrieNode{
        String word;
        TrieNode[] next = new TrieNode[26];
        TrieNode add(char chr){
            if(next[chr-'a'] != null) 
                return next[chr-'a'];
            next[chr-'a'] = new TrieNode();
            return next[chr-'a'];
        }

        boolean ifExists(char chr){
            return (next[chr - 'a']==null)?false:true;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/whdAlive/article/details/81234422
今日推荐