一键导入
algo-bfs
Breadth-first search — shortest path on unweighted graphs, level-order traversal, and the `visited` discipline that prevents O(2^n) blowups.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Breadth-first search — shortest path on unweighted graphs, level-order traversal, and the `visited` discipline that prevents O(2^n) blowups.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Binary search invariants, half-open intervals, and the `lo<hi` template that beats off-by-one bugs.
Depth-first search — recursive vs iterative, recursion-depth gotchas, three-color cycle detection, topological sort.
Dynamic programming — state design, memoization vs tabulation, dimension-reduction, and when DP is the wrong tool.
Pick the right traversal — BFS for unweighted shortest path, Dijkstra for weighted, A* for goal-directed, 0/1-BFS for binary weights.
Greedy algorithms — exchange-argument proofs, when greedy beats DP, classic patterns (interval scheduling, Huffman, scheduling).
Hash maps and sets — when O(1) lookup pays off, hash collisions, frozen keys, and hashing custom types.
| name | algo-bfs |
| description | Breadth-first search — shortest path on unweighted graphs, level-order traversal, and the `visited` discipline that prevents O(2^n) blowups. |
| when-to-use | Shortest path on unweighted graphs, level traversal, multi-source spread, word-ladder transformations. |
BFS is the right answer to "shortest number of steps" on an unweighted graph. The dangerous failure mode is forgetting to mark nodes visited when enqueued — pushing duplicates blows the queue up exponentially on cyclic graphs.
visited[v] is true iff v has been enqueued (NOT iff it has
been dequeued — the difference matters).O(V + E) for an adjacency-list representation.O(V) for the queue and visited set.from collections import deque
def shortest_grid_path(grid: list[list[int]],
starts: list[tuple[int, int]]) -> list[list[int]]:
"""Distance from any start to each cell. ``-1`` if unreachable."""
rows, cols = len(grid), len(grid[0])
dist = [[-1] * cols for _ in range(rows)]
q: deque[tuple[int, int]] = deque()
for r, c in starts:
dist[r][c] = 0
q.append((r, c))
while q:
r, c = q.popleft()
for dr, dc in ((1, 0), (-1, 0), (0, 1), (0, -1)):
nr, nc = r + dr, c + dc
if (0 <= nr < rows and 0 <= nc < cols
and dist[nr][nc] == -1 and grid[nr][nc] != 1):
dist[nr][nc] = dist[r][c] + 1
q.append((nr, nc))
return dist
Note the visited check is dist[nr][nc] == -1 and is performed
before enqueueing — never enqueue the same cell twice.
function bfsLevels(start, neighbors) {
const visited = new Set([start]);
let frontier = [start];
const levels = [];
while (frontier.length) {
levels.push(frontier);
const next = [];
for (const u of frontier) {
for (const v of neighbors(u)) {
if (!visited.has(v)) { visited.add(v); next.push(v); }
}
}
frontier = next;
}
return levels;
}
The "two-array level swap" form is more readable than a single queue with a sentinel when the level boundary matters.
b and depth d the
queue grows to O(b^d).q = [start]; visited = {}. Mark the source
visited before the loop, otherwise it can be re-pushed.list.pop(0) instead of deque.popleft(). O(n)
per pop — the whole BFS becomes O(V^2).-1).For shortest weighted path, use Dijkstra; for 0/1-weighted, use
a deque (push-front for 0-weight edges, push-back for 1-weight).