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)
1 public class Solution { 2 private int m; 3 private int n; 4 public boolean exist(char[][] board, String word) { 5 m = board.length; 6 n = board[0].length; 7 boolean[][] visited = new boolean[m][n]; 8 for (int i = 0; i < m; i++) { 9 for (int j = 0; j < n; j++) { 10 if (board[i][j] == word.charAt(0)) { 11 if (dfs(board, i, j, visited, word, 0)) return true; 12 } 13 } 14 } 15 return false; 16 } 17 18 public boolean dfs(char[][] board, int x, int y, boolean[][] visited, String word, int k) { 19 if (k == word.length()) return true; 20 if (x < 0 || y < 0 || x >= m || y >= n) return false; 21 if (visited[x][y] == true) return false; 22 if (board[x][y] != word.charAt(k)) return false; 23 visited[x][y] = true; 24 boolean res = dfs(board, x, y-1, visited, word, k+1) 25 || dfs(board, x, y+1, visited, word, k+1) 26 || dfs(board, x-1, y, visited, word, k+1) 27 || dfs(board, x+1, y, visited, word, k+1); 28 visited[x][y] = false; 29 return res; 30 } 31 }
下面这个code TLE了,但是跟上面那个都没什么区别,不知道为什么(猜测是因为本身用recursion写时间代价就挺大的,我用的时间刚好在TLE的阈值附近,一分成四个,就超了)
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][n]; 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) { boolean bool1 = false, bool2 = false, bool3 = false, bool4 = false; 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; bool1 = dfs(board, x, y-1, visited, word, k+1); //left bool2 = dfs(board, x, y+1, visited, word, k+1); //right bool3 = dfs(board, x-1, y, visited, word, k+1); //up bool4 = dfs(board, x+1, y, visited, word, k+1); //down visited[x][y] = false; return bool1 || bool2 || bool3 || bool4; } }
再贴一个用stack写的DFS,但是想不出来怎么设置之前访问过的一个节点为unvisited(第二遍做的时候想到:在矩阵中找与string第一个元素相同的字符,以此为起点做DFS,这一次DFS过程中设了某个点为visited就不用管如何再设为unvisited,只管能不能找到合适序列return true,如果这样一次DFS遍历了所有点没有找到,说明该起点不对,以下一个点为起点继续找,这时再重新定义一个新的全false的visited矩阵)。具体说来就是下面代码第6行放到循环内
1 public class Solution { 2 public boolean exist(char[][] board, String word) { 3 int m = board.length; 4 int n = board[0].length; 5 Stack<Integer> toVisit = new Stack<Integer>(); 6 boolean[][] visited = new boolean[m][n]; 7 if (word == "") return true; 8 if (m == 0 && n == 0 && word != "") return false; 9 for (int i = 0; i < m; i++) { 10 for (int j = 0; j < n; j++) { 11 if (board[i][j] == word.charAt(0)) { 12 toVisit.push(i * n + j); 13 } 14 } 15 } 16 17 int k = 0; 18 while (!toVisit.empty()) { 19 int root = toVisit.pop(); 20 int x = root / n; 21 int y = root % n; 22 visited[x][y] = true; 23 if (k == word.length() - 1) return true; 24 if (y > 0 && visited[x][y-1] == false && board[x][y-1] == word.charAt(k+1)) { //left 25 toVisit.push(x * n + y - 1); 26 k++; 27 } 28 if (y < n && visited[x][y+1] == false && board[x][y+1] == word.charAt(k+1)) { //right 29 toVisit.push(x * n + y + 1); 30 k++; 31 } 32 if (x > 0 && visited[x-1][y] == false && board[x-1][y] == word.charAt(k+1)) { //up 33 toVisit.push((x - 1) * n + y); 34 k++; 35 } 36 if (x < m && visited[x+1][y] == false && board[x+1][y] == word.charAt(k+1)) { //down 37 toVisit.push((x + 1) * n + y); 38 k++; 39 } 40 } 41 return false; 42 } 43 }