您的位置:首页 > 其它

Leetcode 79. Word Search & 212. Word Search II

2016-09-20 12:49 393 查看


79. Word Search

Total Accepted: 90478 Total Submissions: 371313 Difficulty: Medium

Given a 2D board and a word, find if the word exists in the grid.
The word can 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.
For example,

Given board =
[
['A','B','C','E'],
['S','F','C','S'],
['A','D','E','E']
]

word = 
"ABCCED"
, -> returns 
true
,
word = 
"SEE"
, -> returns 
true
,
word = 
"ABCB"
, -> returns 
false
.

思路:

递归 + 回溯。

每次对比一位。如果match,就call旁边的四个位置去匹配下一位字符。需要一个visited[][]来保证不重复使用;或者临时修改board当前位置的字符串内容。

public class Solution { // 16ms
public boolean exist(char[][] board, String word) {
if (board==null || board.length==0) return false;
if (word==null || word.length()==0) return true;
int m = board.length;
int n = board[0].length;

boolean[][] tab = new boolean[m]
;
boolean res = false;
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
if(helper(board, tab, word, i, j, 0)) return true;
}
}
return false;
}

boolean helper(char[][] board, boolean[][] tab, String word, int row, int col, int pos){
if(pos==word.length()) return true;
if(row<0 || row==board.length || col<0 || col==board[0].length) return false;

if(board[row][col]==word.charAt(pos) && tab[row][col]==false){
tab[row][col]=true;
if(helper(board, tab, word, row+1, col, pos+1)) return true;
if(helper(board, tab, word, row-1, col, pos+1)) return true;
if(helper(board, tab, word, row, col+1, pos+1)) return true;
if(helper(board, tab, word, row, col-1, pos+1)) return true;
tab[row][col]=false;
}
return false;
}
}



212. Word Search II

Total Accepted: 27917 Total Submissions: 131917 Difficulty: Hard

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.

思路一:

遍历words中每个单词,检查在不在board里,如果在则输出。过了大数据,过不了重复的case。

public class Solution {
public List<String> findWords(char[][] board, String[] words) {
List<String> res = new ArrayList<String>();
for(String item : words){
if(exist(board, item)) res.add(item);
}
return res;
}

public boolean exist(char[][] board, String word) {
if (board==null || board.length==0) return false;
if (word==null || word.length()==0) return true;
int m = board.length;
int n = board[0].length;

boolean[][] tab = new boolean[m]
;
boolean res = false;
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
if(helper(board, tab, word, i, j, 0)) return true;
}
}
return false;
}

boolean helper(char[][] board, boolean[][] tab, String word, int row, int col, int pos){
if(pos==word.length()) return true;
if(row<0 || row==board.length || col<0 || col==board[0].length) return false;

if(board[row][col]==word.charAt(pos) && tab[row][col]==false){
tab[row][col]=true;
if(helper(board, tab, word, row+1, col, pos+1)) return true;
if(helper(board, tab, word, row-1, col, pos+1)) return true;
if(helper(board, tab, word, row, col+1, pos+1)) return true;
if(helper(board, tab, word, row, col-1, pos+1)) return true;
tab[row][col]=false;
}
return false;
}
}


改进:利用HashSet保存再转存。过不了大数据。

public class Solution {
public List<String> findWords(char[][] board, String[] words) {
List<String> res = new ArrayList<String>();
Set<String> set = new HashSet<String>();
for(String item : words){
set.add(item);
}

for(String item : set){
if(exist(board, item)) res.add(item);
}
return res;
}

public boolean exist(char[][] board, String word) {
if (board==null || board.length==0) return false;
if (word==null || word.length()==0) return true;
int m = board.length;
int n = board[0].length;

boolean[][] tab = new boolean[m]
;
boolean res = false;
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
if(helper(board, tab, word, i, j, 0)) return true;
}
}
return false;
}

boolean helper(char[][] board, boolean[][] tab, String word, int row, int col, int pos){
if(pos==word.length()) return true;
if(row<0 || row==board.length || col<0 || col==board[0].length) return false;

if(board[row][col]==word.charAt(pos) && tab[row][col]==false){
tab[row][col]=true;
if(helper(board, tab, word, row+1, col, pos+1)) return true;
if(helper(board, tab, word, row-1, col, pos+1)) return true;
if(helper(board, tab, word, row, col+1, pos+1)) return true;
if(helper(board, tab, word, row, col-1, pos+1)) return true;
tab[row][col]=false;
}
return false;
}
}


思路二:

利用Trie。把所有的words都插入Trie中。这样如果当前字符对应的TrieNode不存在,说明words中没有以当前字符开头的单词,相当于对一个位置,一次就check了所有word的匹配。这样基于node存在,说明目前有匹配,然后再call周围的四个位置,是否匹配同理只要看node存不存在就可以了。

代码来自这里。这个代码比programcreek的80MS快多了,原因一是它基于上面的匹配原理,不需要startWith方法(会把每次的字符串都从头走一遍);另外是它有一个isWord属性,每当一个单词输出之后,该值被重写。这样就没有duplicate了。可以说这个代码思路明白简介,方法干练,直击要害。

public class Solution { // 27ms
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
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Backtracking Trie