您的位置:首页 > 其它

Leetcode: Word Search

2014-05-22 23:45 337 查看
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 =

[
["ABCE"],
["SFCS"],
["ADEE"]
]
word = "ABCCED", -> returns true,
word = "SEE", -> returns true,
word = "ABCB", -> returns false.


DFS算法,非常容易TLE,需要一个boolean矩阵来记录是否访问过某个节点。

写DFS主要就是两个方法:用recursion或者Stack, 用recursion会带来time和memory的cost增加,而且因为要用矩阵做argument, 所以非常担心TLE或者MLE的问题。但是用recursion就比较容易使用boolean矩阵,可以比较容易地对某个节点设置visited或者unvisited。而用stack来写呢,cost会小,但是很难用boolean矩阵来设置之前访问过的某个节点为unvisited。所以思来想去,还是用recursion来写。总的时间复杂度最坏是O(m^2*n^2)

version之一:

public class Solution {
private int m;
private int n;
public boolean exist(char[][] board, String word) {
m = board.length;
n = board[0].length;
boolean[][] visited = new boolean[m]
;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (board[i][j] == word.charAt(0)) {
if (dfs(board, i, j, visited, word, 0)) return true;
}
}
}
return false;
}

public boolean dfs(char[][] board, int x, int y, boolean[][] visited, String word, int k) {
if (k == word.length()) return true;
if (x < 0 || y < 0 || x >= m || y >= n) return false;
if (visited[x][y] == true) return false;
if (board[x][y] != word.charAt(k)) return false;
visited[x][y] = true;
boolean res = dfs(board, x, y-1, visited, word, k+1)
|| dfs(board, x, y+1, visited, word, k+1)
|| dfs(board, x-1, y, visited, word, k+1)
|| dfs(board, x+1, y, visited, word, k+1);
visited[x][y] = false;
return res;
}
}


version之二:(这一版是2016年2月14日写的,写的时候29行visited[i][j]=false忘了,这会导致问题,比如["ABCE","SFES","ADEE"] "ABCESEEEFS", Expected true return false, 原因是[i][j]左边邻居访问完了没找到之后,没有把对应visited元素重新设置为false,下边邻居是正确答案,却无法进入左边)

所以visited[][]还不还原要因情况而定,像这种左边下边互相干扰的情况一定要还原

另外visited数组定义可以像下面方法一样放在循环内,也可以像上面方法一样放在循环外,反正每次调用完毕都会设置回false

public class Solution {
char[][] bd;
int m;
int n;
public boolean exist(char[][] board, String word) {
if (board==null || board.length==0 || board[0].length==0) return false;
if (word==null || word.length()==0) return true;
bd = board;
m = board.length;
n = board[0].length;
for (int i=0; i<m; i++) {
for (int j=0; j<n; j++) {
if (bd[i][j] != word.charAt(0)) continue;
boolean[][] visited = new boolean[m]
;
if (DFS(i, j, word, 0, visited)) return true;
}
}
return false;
}

public boolean DFS(int i, int j, String word, int pos, boolean[][] visited) {
if (pos == word.length()) return true;
if (i<0 || i>=m || j<0 || j>=n || visited[i][j] || bd[i][j]!=word.charAt(pos)) return false;
visited[i][j] = true;
boolean result = DFS(i-1, j, word, pos+1, visited)
|| DFS(i, j-1, word, pos+1, visited)
|| DFS(i+1, j, word, pos+1, visited)
|| DFS(i, j+1, word, pos+1, visited);
visited[i][j] = false;
return result;
}
}


O(1)空间的话可以不用visited数组,直接改board

private boolean exist(char[][] board, int i, int j, String word, int ind){
if(ind == word.length()) return true;
if(i > board.length-1 || i <0 || j<0 || j >board[0].length-1 || board[i][j]!=word.charAt(ind))
return false;
board[i][j]='*';
boolean result =    exist(board, i-1, j, word, ind+1) ||
exist(board, i, j-1, word, ind+1) ||
exist(board, i, j+1, word, ind+1) ||
exist(board, i+1, j, word, ind+1);
board[i][j] = word.charAt(ind);
return result;


再贴一个用stack写的DFS,但是想不出来怎么设置之前访问过的一个节点为unvisited(第二遍做的时候想到:在矩阵中找与string第一个元素相同的字符,以此为起点做DFS,这一次DFS过程中设了某个点为visited就不用管如何再设为unvisited,只管能不能找到合适序列return true,如果这样一次DFS遍历了所有点没有找到,说明该起点不对,以下一个点为起点继续找,这时再重新定义一个新的全false的visited矩阵)。具体说来就是下面代码第6行放到循环内

public class Solution {
public boolean exist(char[][] board, String word) {
int m = board.length;
int n = board[0].length;
Stack<Integer> toVisit = new Stack<Integer>();
boolean[][] visited = new boolean[m]
;
if (word == "") return true;
if (m == 0 && n == 0 && word != "") return false;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (board[i][j] == word.charAt(0)) {
toVisit.push(i * n + j);
}
}
}

int k = 0;
while (!toVisit.empty()) {
int root = toVisit.pop();
int x = root / n;
int y = root % n;
visited[x][y] = true;
if (k == word.length() - 1) return true;
if (y > 0 && visited[x][y-1] == false && board[x][y-1] == word.charAt(k+1)) { //left
toVisit.push(x * n + y - 1);
k++;
}
if (y < n && visited[x][y+1] == false && board[x][y+1] == word.charAt(k+1)) { //right
toVisit.push(x * n + y + 1);
k++;
}
if (x > 0 && visited[x-1][y] == false && board[x-1][y] == word.charAt(k+1)) { //up
toVisit.push((x - 1) * n + y);
k++;
}
if (x < m && visited[x+1][y] == false && board[x+1][y] == word.charAt(k+1)) { //down
toVisit.push((x + 1) * n + y);
k++;
}
}
return false;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: