给定一个 m x n
二维字符网格 board
和一个字符串单词 word
。如果 word
存在于网格中,返回 true
;否则,返回 false
。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
示例 1:
输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED" 输出:true
示例 2:
输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE" 输出:true
示例 3:
输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCB" 输出:false
提示:
m == board.length
n = board[i].length
1 <= m, n <= 6
1 <= word.length <= 15
board
和 word
仅由大小写英文字母组成
进阶:你可以使用搜索剪枝的技术来优化解决方案,使其在 board
更大的情况下可以更快解决问题?
Related Topics
数组
回溯
矩阵
word可能以二维矩阵中的任意一个点为起点,所以遍历每一个点作为起点。
递归遍历每一个点是否匹配,需要二维标记数组标记哪一位置被选取,进行回溯。
如果当前字母不匹配,说明这一条路径不通,返回false。
如果当前注明匹配:
已经匹配到最后一个,直接返回true。
不是最后一个,递归当前位置的上下左右四个位置判断,进行递归。
必须保证上下左右位置下标合法,而且没有被访问过。
如果没有找到,回溯,返回false。
class Solution { private int[][] directions = new int[][]{{-1,0},{1,0},{0,-1},{0,1}}; public boolean exist(char[][] board, String word) { int m = board.length; int n = board[0].length; boolean[][] visited = new boolean[m][n]; //判断以board[i][j]为起点 是否能构成单词word for(int i = 0 ; i < m;i++){ for(int j = 0; j < n;j++){ if(exist(board,i,j,word,0,visited)){ return true; } } } return false; } //i ,j表示board递归的位置 index 表示需要找到word中哪一位的字母 public boolean exist(char[][] board,int i,int j,String word,int index,boolean[][] visited){ if(board[i][j] != word.charAt(index)){//字母不匹配 return false; }else if(index == word.length()-1){ //当最后一个字母匹配成功 也就是下标为length-1 表示已经找到 return true; } //匹配成功 word单词没有匹配完 // 标记 visited[i][j] = true; //上下左右 进行递归 int m = board.length; int n = board[0].length; for(int[] direction : directions){ //计算下标 int newi = i+direction[0]; int newj = j+direction[1]; //下标合法 if(newi>=0 && newi < m && newj>=0 && newj < n){ //保证没有被访问过 if(!visited[newi][newj]){ //找到了单词 直接返回 if(exist(board,newi,newj,word,index+1,visited)){ return true; } } } } // 没有找到 回溯 visited[i][j] = false; return false; } } 解答成功: 执行耗时:112 ms,击败了46.12% 的Java用户 内存消耗:39.7 MB,击败了15.46% 的Java用户
改进:可以将标记的布尔类型数组不适用,直接board中进行标记。
先保存board[i][j]
的值,然后用特殊字符#代替,不匹配的时候再回溯回来。(前提:矩阵中只有字母)
class Solution { private int[][] directions = new int[][]{{-1,0},{1,0},{0,-1},{0,1}}; public boolean exist(char[][] board, String word) { int m = board.length; int n = board[0].length; //判断以board[i][j]为起点 是否能构成单词word for(int i = 0 ; i < m;i++){ for(int j = 0; j < n;j++){ if(exist(board,i,j,word,0)){ return true; } } } return false; } public boolean exist(char[][] board,int i,int j,String word,int index){ if(board[i][j] != word.charAt(index)){//字母不匹配 return false; }else if(index == word.length()-1){ //当最后一个字母匹配成功 也就是下标为length-1 表示已经找到 return true; } //匹配成功 word单词没有匹配完 // 标记 char c = board[i][j]; board[i][j]='#'; //上下左右 进行递归 int m = board.length; int n = board[0].length; for(int[] direction : directions){ //计算下标 int newi = i+direction[0]; int newj = j+direction[1]; //下标合法 if(newi>=0 && newi < m && newj>=0 && newj < n){ if(exist(board,newi,newj,word,index+1)){ return true; } } } // 没有找到 回溯 board[i][j] = c; return false; } } 解答成功: 执行耗时:110 ms,击败了48.05% 的Java用户 内存消耗:39.2 MB,击败了35.23% 的Java用户