zoukankan      html  css  js  c++  java
  • 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.

      

  • 相关阅读:
    csp-s 92
    支持smtp/imap smtp/pop3的撞库python撞库脚本
    关于KB2839299 微软补丁前后的kifastcallentry
    (转载)RegSetValueEx设置REG_SZ类型键值时要注意的问题
    x64windows安全机制进程_线程_模块加载回调摘要
    windbg脚本实践3----监控特定进程创建
    windbg脚本实践2----监控特定注册表键值创建和删除
    windbg脚本实践1----监控特定文件创建 删除 读写
    纪念在乙方安全公司的2年_关于杀毒软件和远控的斗争
    文件删除的windows下面的三种路径(轻量级)
  • 原文地址:https://www.cnblogs.com/apanda009/p/7249545.html
Copyright © 2011-2022 走看看