• 212. Word Search II


    Given a 2D board and a list of words from the dictionary, find all words in the board.
    
    Each word must be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once in a word.
    
    For example,
    Given words = ["oath","pea","eat","rain"] and board =
    
    [
      ['o','a','a','n'],
      ['e','t','a','e'],
      ['i','h','k','r'],
      ['i','f','l','v']
    ]
    Return ["eat","oath"].
    Note:
    You may assume that all inputs are consist of lowercase letters a-z.
    
    click to show hint.
    
    You would need to optimize your backtracking to pass the larger test. Could you stop backtracking earlier?
    
    If the current candidate does not exist in all words' prefix, you could stop backtracking immediately. What kind of data structure could answer such query efficiently? Does a hash table work? Why or why not? How about a Trie? If you would like to learn how to implement a basic trie, please work on this problem: Implement Trie (Prefix Tree) first.

    0. 

    Trie数据结构,也就是前缀树。然后dfs时,如果当前形成的单词不在Trie里,就没必要继续dfs下去了。如果当前字符串在trie里,就说明board可以形成这个word。

    这道题很好的体现了Trie的优势:不用Trie, 我们就得把String[] words里面的word一个一个去board里做dfs(以每个点为起点做一次),很耗时。有了Trie,我们可以用Trie存着所有word,然后去board里做一次dfs(以每个点为起点做一次)

    1. return 千万不能要,否则会出如下的错

    Input:

    ["ab","aa"]
    ["aba","baa","bab","aaab","aaa","aaaa","aaba"]

    Expected answer
    ["aaa","aba","aaba","baa","aaab"]
    Your answer
    ["aaa","aba","baa","aaba"]

    aaa被添加之后,return了,导致另一个正确答案aaab不被添加,这跟以前的情况不同,以前都是答案等长,这里不一定

    我觉得这里的复杂度是O(m*n*4^k),因为对于每个cell来说,有4个方向需要探索

    2. 

    有可能board里面有多份某一个word,dfs会把它们都找出来,但是result set只需要添加一次就好了

    有人是这样做的:Set<String> res = new HashSet<String>();

    return的时候: return new ArrayList<String>(res);

    或者去除掉trie中的word

    public class Solution {
        private class TrieNode {
        TrieNode[] next = new TrieNode[26];
        String word;
    }
        private TrieNode buildTrie(String[] words) {
            TrieNode root = new TrieNode();
            for (String word : words) {
                TrieNode cur = root;
                for (char c : word.toCharArray()) {
                    
                    int i = c - 'a';
                    if (cur.next[i] == null) {
                        cur.next[i] = new TrieNode();
                    }
                    cur = cur.next[i];
                }
                cur.word = word;
            }
            return root;
        }
       public List<String> findWords(char[][] board, String[] words) {
            List<String> res = new ArrayList<String>();
            if (board==null || board.length==0 || words==null || words.length==0) return res;
            TrieNode root = buildTrie(words);
            
            for (int i=0; i<board.length; i++) {
                for (int j=0; j<board[0].length; j++) {
                    dfs(res, i, j, board, root);
                }
            }
            return res;
        }
        
        public void dfs(List<String> res, int i, int j, char[][] board, TrieNode root) {
            if (i<0 || j<0 || i>=board.length || j>=board[0].length || 
                board[i][j] == '#' || root.next[board[i][j] - 'a'] == null) return;
            char c = board[i][j];
            board[i][j] = '#';
            root = root.next[c - 'a'];
            if (root.word != null) {
               
                res.add(root.word);
                root.word = null;
            }
            
           
           
            dfs(res, i-1, j, board,  root);
            dfs(res, i+1, j, board,  root);
            dfs(res, i, j-1, board,  root);
            dfs(res, i, j+1, board,  root);
            //cur = cur.substring(0, cur.length()-1);
            board[i][j] = c;
        }
    }
    

    Code Optimization


    UPDATE: Thanks to @dietpepsi we further improved from 17ms to 15ms.

    1. 59ms: Use search and startsWith in Trie class like this popular solution.
    2. 33ms: Remove Trie class which unnecessarily starts from root in every dfs call.
    3. 30ms: Use w.toCharArray() instead of w.charAt(i).
    4. 22ms: Use StringBuilder instead of c1 + c2 + c3.
    5. 20ms: Remove StringBuilder completely by storing word instead of boolean in TrieNode.
    6. 20ms: Remove visited[m][n] completely by modifying board[i][j] = '#' directly.
    7. 18ms: check validity, e.g., if(i > 0) dfs(...), before going to the next dfs.
    8. 17ms: De-duplicate c - a with one variable i.
    9. 15ms: Remove HashSet completely. dietpepsi's idea is awesome.

      

  • 相关阅读:
    linux-centos7-vmware 虚拟机 设置静态 ip 地址,采用 nat 模式,实现连接公网
    mysql_5.7.20 二进制包 在Linux系统中的 安装和配置
    解决windows系统80端口被占用问题
    应用系统架构演变初探
    fastdfs-nginx扩展模块源码分析
    心已落定,入驻博客园
    mac iterm 提示符序列调整
    Background removal with deep learning
    git push fatal: The remote end hung up unexpectedly
    mac sed 使用踩坑实录
  • 原文地址:https://www.cnblogs.com/apanda009/p/7249545.html
Copyright © 2020-2023  润新知