マトリックスは単なる 2D 配列ですが、インタビューでは、地図、ボード、迷路などの グリッド を表すことがよくあります。各セル grid[r][c] はノードであり、その隣のセルは隣接セルです。
grid = [
[1, 1, 0],
[1, 0, 0],
[0, 0, 1]
]
行r、列c、寸法m × n。シンプルですが、その上に構築されたパターンは強力です。
4 つの個別の if ステートメントを記述する代わりに、方向配列 を使用します。
# 4-directional (up, down, left, right)
dirs = [(-1,0), (1,0), (0,-1), (0,1)]
# 8-directional (includes diagonals)
dirs = [(-1,0),(1,0),(0,-1),(0,1),
(-1,-1),(-1,1),(1,-1),(1,1)]
for dr, dc in dirs:
nr, nc = r + dr, c + dc
if 0 <= nr < m and 0 <= nc < n:
# process neighbour
これは、グリッド問題の中で最も再利用可能なスニペットです。
BFS は、重み付けされていないグリッドで 最短パス を見つけます。ソースから開始して、距離 1 にあるすべての近傍を探索し、次に距離 2 というように探索します。
from collections import deque
def shortest_path(grid, start, end):
m, n = len(grid), len(grid[0])
q = deque([(start[0], start[1], 0)])
visited = {(start[0], start[1])}
dirs = [(-1,0),(1,0),(0,-1),(0,1)]
while q:
r, c, dist = q.popleft()
if (r, c) == end:
return dist
for dr, dc in dirs:
nr, nc = r+dr, c+dc
if 0<=nr<m and 0<=nc<n and (nr,nc) not in visited and grid[nr][nc]==0:
visited.add((nr, nc))
q.append((nr, nc, dist+1))
return -1
塗りつぶし (ペイント バケツ ツールと同様): 開始セルから、同じ色の接続されているすべてのセルを変更します。 DFS または BFS は両方とも機能します。
島の数: グリッドをスキャンします。 1 を見つけたら、DFS/BFS を実行して島全体を訪問済みとしてマークし、カウントを増やします。
def num_islands(grid):
count = 0
for r in range(len(grid)):
for c in range(len(grid[0])):
if grid[r][c] == '1':
dfs(grid, r, c) # mark island
count += 1
return count
ログイン ディスカッションに参加
「島の数」で、DFS 中にセルを訪問済みとしてマークするのはなぜですか?
最初に腐ったオレンジはすべてソースになります。それらをすべて時間 0 でキューにプッシュし、次に BFS にプッシュします。各レベルは 1 分です。列が空になったら、新鮮なオレンジが残っているかどうかを確認します。
Minute 0: [2, 1, 1] 2 = rotten, 1 = fresh
[1, 1, 0]
[0, 1, 1]
Minute 4: [2, 2, 2] All reachable oranges rotten
[2, 2, 0]
[0, 2, 2]
重要な洞察: マルチソース BFS は、1 つのノードではなく複数のノードから同時に開始されます。
「Rotting Oranges」と標準の BFS の違いは何ですか?
右→下→左→上という螺旋の順序でマトリックスを歩き、パスごとに境界を縮小します。
def spiral(matrix):
res = []
top, bot = 0, len(matrix) - 1
left, right = 0, len(matrix[0]) - 1
while top <= bot and left <= right:
for c in range(left, right + 1):
res.append(matrix[top][c])
top += 1
for r in range(top, bot + 1):
res.append(matrix[r][right])
right -= 1
if top <= bot:
for c in range(right, left - 1, -1):
res.append(matrix[bot][c])
bot -= 1
if left <= right:
for r in range(bot, top - 1, -1):
res.append(matrix[r][left])
left += 1
return res
N×N 行列をその場で時計回りに回転します。転置 ([r][c] を [c][r] と交換)、各行を反転します。
Original → Transpose → Reverse rows
1 2 3 1 4 7 7 4 1
4 5 6 → 2 5 8 → 8 5 2
7 8 9 3 6 9 9 6 3
2 つの一般的なバリエーション:
一意のパス: 左上から右下まで、右または下にのみ移動するパスをカウントします。 dp[r][c] = dp[r-1][c] + dp[r][c-1]。
最小パス合計: 同じ考え方ですが、最小の受信パスを選択します。
これらは、多くの場合、2D 動的プログラミングへの最も穏やかな入門書となります。
Unique Paths 問題では、任意の列 c の dp[0][c] は何ですか?
|パターン |テクニック |重要な問題 | |----------|-----------|---------------| |最短パス (重み付けなし) | BFS |迷路の最短経路 | |接続されたコンポーネント | DFS / BFS |島の数 | |マルチソースの広がり |マルチソース BFS |腐ったオレンジ |走査順序 |境界ポインタ |スパイラルマトリックス | |インプレース変換 |トランスポーズ + リバース |画像を回転 | |パスを数える | DP |ユニークなパス | |並べ替えられたグリッドで検索 |階段/二分探索 | 2D マトリックスを検索 |