题目:
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
.
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.
链接: http://leetcode.com/problems/word-search-ii/
题解:
使用Word Search的方法会超时。因为对每一个word我们都要对整个board进行一遍dfs,所以对于每个单词我们的Time Complexity - O(mn * 26L),大集合的话时间会很长,所以不能用这个方法。
据提示我们尝试使用Tire来做。用words里所有的word先建立好Trie,然后再用DFS扫描board就可以了。为什么我们要使用Trie呢?我觉得主要是因为搜索完一个单词之后,可以继续搜索下一个单词,而不用向Brute force搜索完以后要回头重新查找。举个例子,假如单词为sea,seafood,那么搜索到sea后,我们可以继续搜索seafood。 需要注意的是回溯的时候我们依然要进行剪枝操作。访问过的节点,我们和Word Search一样,先mark为"#",dfs之后再mark回来。搜索到的单词,我们可以把isWord设为false,这样可以处理duplicate。这道题目值得好好理解,整理思路。最近做的一些题目都是动不动就要70+ 行, 希望努力修炼能够有所进步,思维和coding能力。
Time Complexity - O(mn * 26L), Space Complexity - O(26L) <<- 复杂度二刷的时候还要好好分析
public class Solution { private TrieNode root; private class TrieNode { private final int R = 26; // Radix R = 26 public boolean isWord; public TrieNode[] next; public TrieNode() { next = new TrieNode[R]; } } public List<String> findWords(char[][] board, String[] words) { List<String> res = new ArrayList<>(); if(board == null || board.length == 0) return res; root = new TrieNode(); for(String word : words) // build Trie addWords(word); StringBuilder sb = new StringBuilder(); // try assemble word for(int i = 0; i < board.length; i++) { for(int j = 0; j < board[0].length; j++) { search(res, sb, root, board, i, j); } } return res; } private void addWords(String word) { if(word == null || word.length() == 0) return; int d = 0; TrieNode node = root; while(d < word.length()) { char c = word.charAt(d); if(node.next[c - 'a'] == null) node.next[c - 'a'] = new TrieNode(); node = node.next[c - 'a']; d++; } node.isWord = true; } private void search(List<String> res, StringBuilder sb, TrieNode node, char[][] board, int i, int j) { if(i < 0 || j < 0 || i >= board.length || j >= board[0].length) return; if(board[i][j] == '#') // pruning return; char c = board[i][j]; TrieNode curRoot = node.next[c - 'a']; // set node here for DFS if(curRoot == null) return; sb.append(c); if(curRoot.isWord == true) { curRoot.isWord = false; res.add(sb.toString()); } board[i][j] = '#'; // mark visited cell to '#' search(res, sb, curRoot, board, i + 1, j); search(res, sb, curRoot, board, i - 1, j); search(res, sb, curRoot, board, i, j + 1); search(res, sb, curRoot, board, i, j - 1); sb.setLength(sb.length() - 1); board[i][j] = c; // backtracking } }
Reference:
https://leetcode.com/discuss/36411/27-lines-uses-complex-numbers
https://leetcode.com/discuss/36337/my-simple-and-clean-java-code-using-dfs-and-trie