9549dbb266
I've subtly been implementing breadth-first traversals in graphs incorrectly. The change is subtle, but updating `seen` needs to happen immediately after queuing an item. The results will remain the same, but the runtimes will differ dramatically. I didn't notice this until I attempted to complete LeetCode's "count islands" challenge, and LeetCode rejected my solution because it could not finish before timing out. After looking at other candidates' solutions and comparing them to mine, I couldn't see any difference... except for this subtle difference. This SO answer provides a helpful explanation: https://stackoverflow.com/questions/45623722/marking-node-as-visited-on-bfs-when-dequeuing The take-away lesson here is to always call `seen.add(..)` immediately after enqueuing.
53 lines
1.6 KiB
Python
53 lines
1.6 KiB
Python
from collections import deque
|
|
|
|
def maybe_queue(row, col, game, q, seen):
|
|
"""
|
|
Add coordinate, (`row`, `col`), to the queue, `q`, as long as it exists in
|
|
the map, `game`, and it is not already present in `seen`.
|
|
"""
|
|
if row >= 0 and row < len(game) and col >= 0 and col < len(game[0]):
|
|
if game[row][col] == 'L' and (row, col) not in seen:
|
|
q.append((row, col))
|
|
seen.add((row, col))
|
|
|
|
def visit_island(row, col, game, seen):
|
|
"""
|
|
Starting at the coordinate, (`row`, `col`), in the map, `game`, visit all
|
|
surrounding tiles marked as land by adding them to the `seen` set.
|
|
"""
|
|
q = deque()
|
|
q.append((row, col))
|
|
while q:
|
|
row, col = q.popleft()
|
|
maybe_queue(row - 1, col, game, q, seen) # UP
|
|
maybe_queue(row + 1, col, game, q, seen) # DOWN
|
|
maybe_queue(row, col - 1, game, q, seen) # LEFT
|
|
maybe_queue(row, col + 1, game, q, seen) # RIGHT
|
|
|
|
def count_islands(game):
|
|
"""
|
|
Return the number of contiguous land tiles in the map, `game`.
|
|
"""
|
|
result = 0
|
|
seen = set()
|
|
for row in range(len(game)):
|
|
for col in range(len(game[row])):
|
|
if game[row][col] == 'L' and (row, col) not in seen:
|
|
visit_island(row, col, game, seen)
|
|
result += 1
|
|
return result
|
|
|
|
################################################################################
|
|
# Tests
|
|
################################################################################
|
|
|
|
game = [
|
|
"LWLWWW",
|
|
"LLLWWW",
|
|
"WWWLLW",
|
|
]
|
|
|
|
result = count_islands(game)
|
|
print(result)
|
|
assert result == 2
|
|
print("Success!")
|