Leetcode: 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"].

如果跟Word Search做法一样,还按照DFS回溯的方法,逐个检查每个word是否在board里,显然效率是比较低的。我们可以利用Trie数据结构,也就是前缀树。然后dfs时,如果当前形成的单词不在Trie里,就没必要继续dfs下去了。如果当前字符串在trie里,就说明board可以形成这个word。

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

 

需要小心的几点,我犯了错误:

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

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

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

2. 第21行 string concatenation actually creates a new string, and have the reference cur refer to the new string. It does not change the original content, so no changes will cause to the original content after the recursion. We do not need to do string shrinking like this cur = cur.substring(0, cur.length()-1) at the end of the recursion;

To be specific: suppose String str = "ab" is the original content, we use str to be the argument to call function dfs. In dfs function, String cur gets the reference to original object "ab". Now both String str and String cur refers to the original "ab". Now we do: cur = cur + 'a'. The '+' actually creates a deep copy of "ab" in the memory with the content "aba", an entirely new String object. And we assign reference cur to this new String object. Whatever changes we do to the new string object referred by cur, it does not influence the original string object str. So at the end of the dfs function, we either shrink or not shrink cur, it simply doesn't matter.

 

以下为犯的错误:

9行visited数组可以定义在循环里,或者直接class 中,反正每到一个新的entry(i,j), visited数组都是全false

 

3. 26行 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个方向需要探索
 1     public List<String> findWords(char[][] board, String[] words) {
 2         List<String> res = new ArrayList<String>();
 3         if (board==null || board.length==0 || words==null || words.length==0) return res;
 4         Trie trie = new Trie();
 5         for (String str : words) {
 6             trie.insert(str);
 7         }
 8         
 9         boolean[][] visited = new boolean[board.length][board[0].length];
10         for (int i=0; i<board.length; i++) {
11             for (int j=0; j<board[0].length; j++) {
12                 dfs(res, "", i, j, board, visited, trie);
13             }
14         }
15         return res;
16     }
17     
18     public void dfs(List<String> res, String cur, int i, int j, char[][] board, boolean[][] visited, Trie trie) {
19         if (i<0 || j<0 || i>=board.length || j>=board[0].length) return;
20         if (visited[i][j]) return;
21         cur += board[i][j];
22         if (!trie.startsWith(cur)) return;
23         if (trie.search(cur)) {
24             if (!res.contains(cur))
25                 res.add(cur);
26             //return;
27         }
28         //cur = cur + board[i][j];
29         visited[i][j] = true;
30         dfs(res, cur, i-1, j, board, visited, trie);
31         dfs(res, cur, i+1, j, board, visited, trie);
32         dfs(res, cur, i, j-1, board, visited, trie);
33         dfs(res, cur, i, j+1, board, visited, trie);
34         //cur = cur.substring(0, cur.length()-1);
35         visited[i][j] = false;
36     }

 The Trie structure is still as:

 1     class TrieNode {
 2         // Initialize your data structure here.
 3         int num; //How many words go through this TrieNode
 4         TrieNode[] son; //collection of sons
 5         boolean isEnd;
 6         char val;
 7         
 8         public TrieNode() {
 9             this.num = 0;
10             this.son = new TrieNode[26];
11             this.isEnd = false;
12         }
13     }
14 
15     public class Trie {
16         private TrieNode root;
17     
18         public Trie() {
19             root = new TrieNode();
20         }
21     
22         // Inserts a word into the trie.
23         public void insert(String word) {
24             if (word==null || word.length()==0) return;
25             char[] arr = word.toCharArray();
26             TrieNode node = this.root;
27             for (int i=0; i<arr.length; i++) {
28                 int pos = (int)(arr[i] - 'a');
29                 if (node.son[pos] == null) {
30                     node.son[pos] = new TrieNode();
31                     node.son[pos].num++;
32                     node.son[pos].val = arr[i];
33                 }
34                 else {
35                     node.son[pos].num++;
36                 }
37                 node = node.son[pos];
38             }
39             node.isEnd = true;
40         }
41     
42         // Returns if the word is in the trie.
43         public boolean search(String word) {
44             char[] arr = word.toCharArray();
45             TrieNode node = this.root;
46             for (int i=0; i<arr.length; i++) {
47                 int pos = (int)(arr[i] - 'a');
48                 if (node.son[pos] == null) return false;
49                 node = node.son[pos];
50             }
51             return node.isEnd;
52         }
53     
54         // Returns if there is any word in the trie
55         // that starts with the given prefix.
56         public boolean startsWith(String prefix) {
57             char[] arr = prefix.toCharArray();
58             TrieNode node = this.root;
59             for (int i=0; i<arr.length; i++) {
60                 int pos = (int)(arr[i] - 'a');
61                 if (node.son[pos] == null) return false;
62                 node = node.son[pos];
63             }
64             return true;
65         }
66     }
67     
68     // Your Trie object will be instantiated and called as such:
69     // Trie trie = new Trie();
70     // trie.insert("somestring");
71     // trie.search("key");

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值