【发布时间】:2022-11-10 00:26:49
【问题描述】:
背景
- 我正在二维网格中搜索一个单词。
- 我们可以左/右和上/下搜索。
- 例如,在这个网格中,从
(0,0)开始搜索"abef"将返回True
示例(网格 1):
我在哪里
- 递归版本给出了预期的结果(见下面的
dfs_rec())。 - 迭代版本也给出了预期的结果(见下面的
dfs_iter())。然而,在这个版本中,我将visited集的副本复制到每个节点的堆栈上。
我的问题是
- 有没有办法避免在迭代版本中复制 (
visited.copy()),并在递归版本中添加/删除单个visited集?
更多细节和我尝试过的东西......
-
在
dfs_rec()中有一个名为visited的set(),它通过visited.add((row,col))和visited.remove((row,col))进行了更改 -
但是在
dfs_iter()中,我每次都将visited.copy()推入堆栈,以防止节点被错误地标记为已访问。 -
我已经看到了一些迭代示例,其中他们使用单个
visited集合,而不复制或从集合中删除任何内容,但这并没有在这些示例中给我正确的输出(请参阅下面的grid3使用grid3)。
例如,以这个网格为例:
- 假设你搜索
"abexxxxxx"(覆盖整个网格),预期输出将是True
-
但是
dfs_iter_nocopy()将在grid2或grid3之一上给出不正确的输出(它们只是镜像,一个会通过,一个会失败),具体取决于您将节点推入堆栈的顺序。 -
发生的事情是,当您搜索
"abexxxxxx"时,它会搜索这样的路径(仅命中 5 个 x,而需要 6 个)。
- 它将
(1,0)处的x标记为已访问,当需要搜索该分支时,它会停在(1,0),如下所示:
代码
def width (g): return len(g)
def height (g): return len(g[0])
def valid (g,r,c): return r>=0 and c>=0 and r<height(g) and c<width(g)
def dfs_rec (grid, word, row, col, visited):
if not valid(grid, row, col): return False # (row,col) off board
if (row,col) in visited: return False # already checked
if grid[row][col] != word[0]: return False # not right path
if grid[row][col] == word: # len(word)==1
return True
visited.add((row,col))
if dfs_rec(grid, word[1:], row, col+1, visited): return True
if dfs_rec(grid, word[1:], row+1, col, visited): return True
if dfs_rec(grid, word[1:], row, col-1, visited): return True
if dfs_rec(grid, word[1:], row-1, col, visited): return True
# Not found on this path, don't block for other paths
visited.remove((row,col))
return False
def dfs_iter (grid, start_word, start_row, start_col, start_visited):
stack = [ (start_row, start_col, start_word, start_visited) ]
while len(stack) > 0:
row,col,word,visited = stack.pop()
if not valid(grid, row, col): continue
if (row,col) in visited: continue
if grid[row][col] != word[0]: continue
if grid[row][col] == word:
return True
visited.add((row,col))
stack.append( (row, col+1, word[1:], visited.copy()) )
stack.append( (row+1, col, word[1:], visited.copy()) )
stack.append( (row, col-1, word[1:], visited.copy()) )
stack.append( (row-1, col, word[1:], visited.copy()) )
return False
def dfs_iter_nocopy (grid, start_word, start_row, start_col):
visited = set()
stack = [ (start_row, start_col, start_word) ]
while len(stack) > 0:
row,col,word = stack.pop()
if not valid(grid, row, col): continue
if (row,col) in visited: continue
if grid[row][col] != word[0]: continue
if grid[row][col] == word:
return True
visited.add((row,col))
stack.append( (row, col+1, word[1:]) )
stack.append( (row+1, col, word[1:]) )
stack.append( (row, col-1, word[1:]) )
stack.append( (row-1, col, word[1:]) )
return False
if __name__ == '__main__':
grid = [ 'abc', 'def', 'hij' ]
grid2 = [ 'abx', 'xex', 'xxx' ]
grid3 = [ 'xba', 'xex', 'xxx' ]
print( dfs_rec(grid, 'abef', 0, 0, set() ) == True )
print( dfs_rec(grid, 'abcd', 0, 0, set() ) == False )
print( dfs_rec(grid, 'abcfjihde', 0, 0, set() ) == True )
print( dfs_rec(grid, 'abefjihd', 0, 0, set() ) == True )
print( dfs_rec(grid, 'abefjihda', 0, 0, set() ) == False )
print( dfs_rec(grid, 'abefjihi', 0, 0, set() ) == False )
print( dfs_iter(grid, 'abc', 0, 0, set() ) == True )
print( dfs_iter(grid, 'abef', 0, 0, set() ) == True )
print( dfs_iter(grid, 'abcd', 0, 0, set() ) == False )
print( dfs_iter(grid, 'abcfjihde', 0, 0, set() ) == True )
print( dfs_iter(grid, 'abefjihd', 0, 0, set() ) == True )
print( dfs_iter(grid, 'abefjihda', 0, 0, set() ) == False )
print( dfs_iter(grid, 'abefjihi', 0, 0, set() ) == False )
print( dfs_rec(grid2, 'abexxxxxx', 0, 0, set() ) == True )
print( dfs_iter(grid2, 'abexxxxxx', 0, 0, set() ) == True )
print( dfs_iter_nocopy(grid2, 'abexxxxxx', 0, 0 ) == True )
print( dfs_rec(grid3, 'abexxxxxx', 0, 2, set() ) == True )
print( dfs_iter(grid3, 'abexxxxxx', 0, 2, set() ) == True )
print( dfs_iter_nocopy(grid3, 'abexxxxxx', 0, 2 ) == True ) # <-- Problem, prints False
【问题讨论】:
-
您需要将您称为
visited.add的指标推送到您的stack上。当您弹出该指标时,您需要调用visited.remove。
标签: python algorithm graph-theory depth-first-search tree-search