Javascript 使用矩阵的正确方法是什么?
我做这个练习题是为了找出矩阵中是否存在一个单词,这让我意识到我并不完全理解DFS 在破解编码面试时,DFS的伪代码为:Javascript 使用矩阵的正确方法是什么?,javascript,algorithm,recursion,depth-first-search,Javascript,Algorithm,Recursion,Depth First Search,我做这个练习题是为了找出矩阵中是否存在一个单词,这让我意识到我并不完全理解DFS 在破解编码面试时,DFS的伪代码为: void search(Node root) { if (root == null) return; visit(root); root.visited = true; for each (Node n in root.adjacent) { if (n.visited == false) { search(n); } } }
void search(Node root) {
if (root == null) return;
visit(root);
root.visited = true;
for each (Node n in root.adjacent) {
if (n.visited == false) {
search(n);
}
}
}
对我来说,这看起来像是一种格式:
dfs()
:
这更简洁,但对我来说更难理解。第一个版本dfs()
执行循环,并在递归之前提前释放邻居,这对我来说更有意义。第二个版本没有循环,因此它在当前节点上执行所有检查
我注意到的第一件事是,在大多数涉及网格的问题中,解决方案都涉及递归后的“取消标记”。为什么会这样?这是否仅适用于“单词搜索问题”等特定情况,您可能希望将来以其他路径重新访问节点?
哪个是正确的,dfs()
或dfs2()
?
下面是全部内容:
var dirs = [
[0,1], // r
[1,0], // d
[0,-1], // u
[-1,0], // l
];
var wsBoard = [
['A','B','C','E'],
['S','F','C','S'],
['A','D','E','E']
];
var exist = function(board, word, version) {
for (var r = 0; r < board.length; r++) {
for (var c = 0; c < board[0].length; c++) {
if (board[r][c] === word[0])
if (dfs(r, c, 0)) return true;
// if (dfs2(r, c, 0)) return true;
}
}
return false;
function dfs(r, c, i) {
console.log(`(${r},${c})\t${i}: ${word[i]}`);
// goal
if (i === word.length-1) return true;
// mark
board[r][c] = '#';
// loop and recurse each neighbor
for (var d of dirs) {
var nr = r + d[0];
var nc = c + d[1];
// bail early if neighbor does not meet conditions
if (nr < 0 || nc < 0 || nr >= board.length || nc >= board[0].length) continue; // neighbor is out of bounds
if (board[nr][nc] === '#') continue; // neighbor already visited
if (board[nr][nc] !== word[i+1]) continue; // neighbor does not meet goal
console.log(board);
// recursion
var result = dfs(nr, nc, i+1);
// un-mark
board[r][c] = word[i];
return result;
}
}
function dfs2(r, c, i) {
console.log(`(${r},${c})\t${i}: ${word[i]}`);
// goal
if (i === word.length) return true;
// bail early if current does not meet conditions
if (r < 0 || c < 0 || r >= board.length || c >= board[0].length) return false; // current is out of bounds
if (board[r][c] === '#') return false; // current already visited
if (board[r][c] !== word[i]) return false; // current does not meet goal
// mark
board[r][c] = '#';
console.log(board);
// recursion
var result = dfs2(r+1, c, i+1) || dfs2(r-1, c, i+1) || dfs2(r, c+1, i+1) || dfs2(r, c-1, i+1);
// un-mark
board[r][c] = word[i];
return result;
}
};
console.log(exist(wsBoard, 'ABCCED')); // => true
console.log(exist(wsBoard, 'SEE')); // => true
console.log(exist(wsBoard, 'ABCB')); // => false
var-dirs=[
[0,1],//r
[1,0],//d
[0,-1],//u
[-1,0],//l
];
var wsBoard=[
[A'、'B'、'C'、'E'],
[S'、'F'、'C'、'S'],
['A','D','E','E']
];
var exist=功能(板、字、版本){
对于(var r=0;r=board.length | | nc>=board[0].length)继续;//邻居超出范围
如果(线路板[nr][nc]='#')继续;//已访问邻居
如果(board[nr][nc]!==word[i+1])继续;//邻居未达到目标
控制台.日志(板);
//递归
var结果=dfs(nr、nc、i+1);
//un标记
板[r][c]=字[i];
返回结果;
}
}
函数dfs2(r、c、i){
log(`(${r},${c})\t${i}:${word[i]}`);
//目标
如果(i==word.length)返回true;
//如果电流不符合条件,则提前保释
如果(r<0 | | c<0 | | r>=board.length | | c>=board[0].length)返回false;//当前值超出范围
如果(线路板[r][c]='#')返回false;//当前已访问
if(board[r][c]!==word[i])返回false;//当前未达到目标
//标记
董事会[r][c]=“#”;
控制台.日志(板);
//递归
var结果=dfs2(r+1,c,i+1)| | dfs2(r-1,c,i+1)| | dfs2(r,c+1,i+1)| | dfs2(r,c-1,i+1);
//un标记
板[r][c]=字[i];
返回结果;
}
};
console.log(存在(wsBoard,'ABCCED'));//=>真的
log(存在(wsBoard,'SEE');//=>真的
console.log(存在(wsBoard,'ABCB'));//=>假的
我相信,尽管dfs
和dfs2
都基于相同的理念dfs
有一个缺陷,但它只返回第一条路径的探索结果
看看这个例子,我试图在黑板上找到FOO
,很明显,它是第一列,但是您的实现返回false
var-dirs=[
[0,1],//r
[1,0],//d
[0,-1],//u
[-1,0],//l
];
var板=[
[F'、'O'、'X'],
[O','','',],
['O','',']
];
var exist=函数(字){
功能dfs(r、c、i){
//标记
董事会[r][c]=“#”;
//目标
如果(i==word.length-1)返回true;
//循环并递归每个邻居
for(dirs的var d){
var-nr=r+d[0];
var nc=c+d[1];
//若邻居不符合条件,则提前保释
如果(nr<0 | | nc<0 | | nr>=board.length | | nc>=board[0].length)继续;//邻居超出范围
如果(线路板[nr][nc]='#')继续;//已访问邻居
如果(board[nr][nc]!==word[i+1])继续;//邻居未达到目标
//递归
var结果=dfs(nr、nc、i+1);
//un标记
板[r][c]=字[i];
返回结果;
}
}
对于(var r=0;r log(exist('FOO'))
太棒了!是的,我开始做后续问题“给定一本字典查找所有单词”(DFS和Trie),并意识到我很容易用dfs2()
,但它一直用DFS()
失败。我以为我走远了,但那是你发现的虫子。谢谢还感谢您对取消标记的深入了解。对我来说不是那么直观,所以我会继续练习。注意到了其他的东西。取消标记不应该发生在for循环之外吗?Somark;对于(){}取消标记代码>?
function dfs2(r, c, i) {
// goal
if (i === word.length) return true;
// bail early if current does not meet conditions
if (r < 0 || c < 0 || r >= board.length || c >= board[0].length) return false; // current is out of bounds
if (board[r][c] === '#') return false; // current already visited
if (board[r][c] !== word[i]) return false; // current does not meet goal
// mark
board[r][c] = '#';
// recursion
var result = dfs2(r+1, c, i+1) || dfs2(r-1, c, i+1) || dfs2(r, c+1, i+1) || dfs2(r, c-1, i+1);
// un-mark
board[r][c] = word[i];
return result;
}
var dirs = [
[0,1], // r
[1,0], // d
[0,-1], // u
[-1,0], // l
];
var wsBoard = [
['A','B','C','E'],
['S','F','C','S'],
['A','D','E','E']
];
var exist = function(board, word, version) {
for (var r = 0; r < board.length; r++) {
for (var c = 0; c < board[0].length; c++) {
if (board[r][c] === word[0])
if (dfs(r, c, 0)) return true;
// if (dfs2(r, c, 0)) return true;
}
}
return false;
function dfs(r, c, i) {
console.log(`(${r},${c})\t${i}: ${word[i]}`);
// goal
if (i === word.length-1) return true;
// mark
board[r][c] = '#';
// loop and recurse each neighbor
for (var d of dirs) {
var nr = r + d[0];
var nc = c + d[1];
// bail early if neighbor does not meet conditions
if (nr < 0 || nc < 0 || nr >= board.length || nc >= board[0].length) continue; // neighbor is out of bounds
if (board[nr][nc] === '#') continue; // neighbor already visited
if (board[nr][nc] !== word[i+1]) continue; // neighbor does not meet goal
console.log(board);
// recursion
var result = dfs(nr, nc, i+1);
// un-mark
board[r][c] = word[i];
return result;
}
}
function dfs2(r, c, i) {
console.log(`(${r},${c})\t${i}: ${word[i]}`);
// goal
if (i === word.length) return true;
// bail early if current does not meet conditions
if (r < 0 || c < 0 || r >= board.length || c >= board[0].length) return false; // current is out of bounds
if (board[r][c] === '#') return false; // current already visited
if (board[r][c] !== word[i]) return false; // current does not meet goal
// mark
board[r][c] = '#';
console.log(board);
// recursion
var result = dfs2(r+1, c, i+1) || dfs2(r-1, c, i+1) || dfs2(r, c+1, i+1) || dfs2(r, c-1, i+1);
// un-mark
board[r][c] = word[i];
return result;
}
};
console.log(exist(wsBoard, 'ABCCED')); // => true
console.log(exist(wsBoard, 'SEE')); // => true
console.log(exist(wsBoard, 'ABCB')); // => false