对于初学者来说,我并不是想问the difference between a car and a DeLorean。因此,我正在解决this LeetCode问题:
给出一个2D板和一个单词,查找单词是否存在于网格中。 该单词可以由顺序相邻的单元格的字母构成,其中“相邻”单元格是水平或垂直相邻的单元格。同一字母单元不得重复使用。
board =
[
['A','B','C','E'],
['S','F','C','S'],
['A','D','E','E']
]
给出单词=“ ABCCED”,返回true。
public class Solution {
public boolean exist(char[][] board, String word) {
for(int i = 0; i < board.length; i++)
for(int j = 0; j < board[0].length; j++){
if(exist(board, i, j, word, 0))
return true;
}
return false;
}
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); //--> why?
return result;
}
我的问题是-与使用正常的递归DFS相比,对此问题使用回溯算法的直觉是什么?在使用递归DFS时,我只需将节点标记为已访问,然后再移至其邻居(从而找出ABCCED
是有效路径)。为什么我必须 backtrack (上面代码中的注释行)来了解该路径是否存在?
谢谢!
编辑:以另一种方式问我的问题:我们为什么不从最上方的左单元格A
开始,然后开始使用{{1}设置标记访问节点的方法?在下一次迭代中,我们可以从最左visited
-A
相邻的单元格开始,使用新的B
设置来标记访问的节点来访问其所有邻居,等等?为什么要使用回溯?
答案 0 :(得分:0)
深度优先搜索是一种回溯算法。 递归的本质是回溯机制本身。如果该路径不是好的路径,则在进入更深的树之前会返回false。 这是您的回溯:
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] = word.charAt(ind);
仅用于将节点重置回其原始值,并允许其在Bakon Jarser在问题文章中评论时在其他相邻路径中使用。
您可以快速查看first paragraph 和this post。
希望获得帮助。
答案 1 :(得分:0)
假设您正在此板上寻找ABCBDE
一词:
ABD
BCE
假设与您提供的源代码中的邻居探索顺序相同,您的DFS首先将尝试使用right-> down-> left路径,因此您的visited
集将包含最左边的2x2正方形,您将无法找到解决方案。