【问题标题】:Infinitely expanding queue in python 3python 3中无限扩展队列
【发布时间】:2023-03-17 17:36:01
【问题描述】:

昨晚我试图解决 leetcode 的 Number of Islands 挑战。我对自己如此迅速地解决它感到非常满意。该解决方案遍历网格的行,直到找到一个有土地的单元格。然后程序进入一个函数,找到所有与陆地(BFS)相邻的单元格,用水替换它们,然后返回。岛屿计数增加,并重复此过程,直到所有细胞都转化为水。

简单吧?但是程序在以下测试用例上停止:

import queue
grid = [
    ["1","1","1","1","1","0","1","1","1","1","1","1","1","1","1","0","1","0","1","1"],
    ["0","1","1","1","1","1","1","1","1","1","1","1","1","0","1","1","1","1","1","0"],
    ["1","0","1","1","1","0","0","1","1","0","1","1","1","1","1","1","1","1","1","1"],
    ["1","1","1","1","0","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1"],
    ["1","0","0","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1"],
    ["1","0","1","1","1","1","1","1","0","1","1","1","0","1","1","1","0","1","1","1"],
    ["0","1","1","1","1","1","1","1","1","1","1","1","0","1","1","0","1","1","1","1"],
    ["1","1","1","1","1","1","1","1","1","1","1","1","0","1","1","1","1","0","1","1"],
    ["1","1","1","1","1","1","1","1","1","1","0","1","1","1","1","1","1","1","1","1"],
    ["1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1"],
    ["0","1","1","1","1","1","1","1","0","1","1","1","1","1","1","1","1","1","1","1"],
    ["1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1"],
    ["1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1"],
    ["1","1","1","1","1","0","1","1","1","1","1","1","1","0","1","1","1","1","1","1"],
    ["1","0","1","1","1","1","1","0","1","1","1","0","1","1","1","1","0","1","1","1"],
    ["1","1","1","1","1","1","1","1","1","1","1","1","0","1","1","1","1","1","1","0"],
    ["1","1","1","1","1","1","1","1","1","1","1","1","1","0","1","1","1","1","0","0"],
    ["1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1"],
    ["1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1"],
    ["1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1"]
]

def print_grid(grid):
    for idxr, row in enumerate(grid):
        for idxc, cell in enumerate(row):
            print(f"[{grid[idxr][idxc]}]", end="")
        print("")

    print("\n----\n")

def nuke_island(grid, idxr, idxc):
    """Traverses and destroys an island."""
    # Create a queue of our first cell
    island_cells = queue.Queue()
    island_cells.put((idxr, idxc))

    # Process our queue
    while not island_cells.empty():
        # Retrieve a new cell from queue
        idxr, idxc = island_cells.get()

        # Replace new cell with water
        grid[idxr][idxc] = "0"

        #Try to add all valid connecting cells to the queue
        for row, col in [(idxr-1, idxc), (idxr+1, idxc), (idxr, idxc-1), (idxr, idxc+1)]:
            # Don't allow python to backwards-index
            if row < 0 or col < 0:
                continue
            try:
                # Retieve the connecting cell
                cell = grid[row][col]

                # If the cell is land, add it to the queue
                if cell == "1":
                    island_cells.put((row, col))

            except IndexError:
                # We went off the map, continue
                continue

    # We've processed all connecting cells and nuked the whole island, return updated grid
    return grid

# Set number of islands to zero
islands = 0

# Iterate through the grid
for idxr, row in enumerate(grid):
    for idxc, cell in enumerate(row):
        # If our cell is land, enter nuke_island
        if cell == '1':
            grid = nuke_island(grid, idxr, idxc)
            islands += 1

# Return the number of total islands
print(f"Islands: {islands}")

如果您查看上面的示例,您可以看到网格只有一个岛。 程序从单元格 [0][0] 开始,进入 nuke_island() 子程序,然后卡在那里。 如果您使用 print_grid() 调试功能,您可以看到程序将陆地单元格删除为预计到某一点,然后停止。问题是队列“island_cells”。

由于某种原因,队列的增长速度比删除项目的速度还要快,并且会永远增长。我不知道为什么,因为以前的测试用例不会发生这种情况,甚至以前的测试用例只有一个岛。 如果我用代码中的列表替换队列:

grid = [
    ["1","1","1","1","1","0","1","1","1","1","1","1","1","1","1","0","1","0","1","1"],
    ["0","1","1","1","1","1","1","1","1","1","1","1","1","0","1","1","1","1","1","0"],
    ["1","0","1","1","1","0","0","1","1","0","1","1","1","1","1","1","1","1","1","1"],
    ["1","1","1","1","0","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1"],
    ["1","0","0","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1"],
    ["1","0","1","1","1","1","1","1","0","1","1","1","0","1","1","1","0","1","1","1"],
    ["0","1","1","1","1","1","1","1","1","1","1","1","0","1","1","0","1","1","1","1"],
    ["1","1","1","1","1","1","1","1","1","1","1","1","0","1","1","1","1","0","1","1"],
    ["1","1","1","1","1","1","1","1","1","1","0","1","1","1","1","1","1","1","1","1"],
    ["1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1"],
    ["0","1","1","1","1","1","1","1","0","1","1","1","1","1","1","1","1","1","1","1"],
    ["1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1"],
    ["1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1"],
    ["1","1","1","1","1","0","1","1","1","1","1","1","1","0","1","1","1","1","1","1"],
    ["1","0","1","1","1","1","1","0","1","1","1","0","1","1","1","1","0","1","1","1"],
    ["1","1","1","1","1","1","1","1","1","1","1","1","0","1","1","1","1","1","1","0"],
    ["1","1","1","1","1","1","1","1","1","1","1","1","1","0","1","1","1","1","0","0"],
    ["1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1"],
    ["1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1"],
    ["1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1"]
]

def print_grid(grid):
    for idxr, row in enumerate(grid):
        for idxc, cell in enumerate(row):
            print(f"[{grid[idxr][idxc]}]", end="")
        print("")

    print("\n----\n")

def nuke_island(grid, idxr, idxc):
    """Traverses and destroys an island."""
    # Create a list of our first cell
    island_cells = [(idxr, idxc)]

    # Process our list
    while len(island_cells) > 0:
        # Retrieve a new cell from queue
        (idxr, idxc) = island_cells.pop()

        # Replace new cell with water
        grid[idxr][idxc] = "0"

        # Try to add all valid connecting cells to the queue
        for (row, col) in [(idxr-1, idxc), (idxr+1, idxc), (idxr, idxc-1), (idxr, idxc+1)]:
            # Don't allow python to backwards-index
            if row < 0 or col < 0:
                continue
            try:
                # Retieve the connecting cell
                cell = grid[row][col]

                # If the cell is land, add it to the queue
                if cell == "1":
                    island_cells.append((row, col))

            except IndexError:
                # We went off the map, continue
                continue

    # We've processed all connecting cells and nuked the whole island, return updated grid
    return grid

# Set number of islands to zero
islands = 0

# Iterate through the grid
for idxr, row in enumerate(grid):
    for idxc, cell in enumerate(row):
        # If our cell is land, enter nuke_island
        if cell == '1':
            grid = nuke_island(grid, idxr, idxc)
            islands += 1

# Return the number of total islands
print(f"Islands: {islands}")

程序现在按预期运行。 即使我将列表与 FIFO 队列互换使用。那么发生了什么?为什么队列无限增长?我错过了什么明显的东西吗?

【问题讨论】:

  • append(...) / pop() 实际上是 LIFO 而不是 FIFO 所以你已经切换到 DFS
  • 是的,我刚刚注意到了!我来这里是为了更新问题。尽管如此,为什么使用 BFS 会永远挂起并且似乎不断地将项目添加到队列中?只有 400 个单元格。
  • 可能你从来没有重复数据删除——你需要调试它(这与 stackoverflow 无关)

标签: python python-3.x list queue breadth-first-search


【解决方案1】:

我知道出了什么问题。正如 Anthony 指出的那样,由于没有使用 list.pop(0),我实际上使用的是 LIFO (DFS) 而不是 FIFO (BFS)。当我切换到 LifoQueue() 时,程序按预期工作。

其次,我没有检查邻居是否已经在队列中,因此我添加了重复的条目。进行检查解决了问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-24
    • 2015-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-18
    • 1970-01-01
    相关资源
    最近更新 更多