🏠 总目录📚 本教程 06 · 回溯与矩阵:试完一条路怎么干净回来 ← →
📑 本页目录(点开跳转)

06 · 回溯与矩阵:试完一条路怎么干净回来

⏱ 10 分钟 | 矩阵路径、机器人范围、排列


🎯 一句话

回溯的关键动作不是“递归调用”,而是:做选择 → 向下试 → 撤销选择。

🧩 题 1:矩阵中的路径

从每个格子尝试;当前字符匹配才继续走四个方向。一个格子在当前路径中不能重复使用,所以进来标记、离开还原。

def has_path(board, word):
    rows, cols = len(board), len(board[0])

    def visit(r, c, index):
        if index == len(word):
            return True
        if not (0 <= r < rows and 0 <= c < cols) or board[r][c] != word[index]:
            return False
        saved, board[r][c] = board[r][c], '#'
        found = any(visit(r + dr, c + dc, index + 1) for dr, dc in ((1, 0), (-1, 0), (0, 1), (0, -1)))
        board[r][c] = saved
        return found

    return any(visit(r, c, 0) for r in range(rows) for c in range(cols))


grid = [list('ABCE'), list('SFCS'), list('ADEE')]
assert has_path(grid, 'ABCCED') is True
assert has_path(grid, 'ABCB') is False

🧩 题 2:机器人的运动范围

条件变成“坐标位数之和不超过阈值”。能走到一个格子后,再向四周扩展;已经访问过就不用重算。

def moving_count(rows, cols, limit):
    def digit_sum(value):
        return sum(map(int, str(value)))

    seen, stack = set(), [(0, 0)]
    while stack:
        r, c = stack.pop()
        if (r, c) in seen or not (0 <= r < rows and 0 <= c < cols):
            continue
        if digit_sum(r) + digit_sum(c) > limit:
            continue
        seen.add((r, c))
        stack.extend(((r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)))
    return len(seen)


assert moving_count(3, 3, 1) == 3

🧩 题 3:字符串的排列

每一层决定当前位置放谁;同一层遇到重复字符时跳过,避免产生重复排列。

def permutations(text):
    answer = []

    def choose(prefix, rest):
        if not rest:
            answer.append(prefix)
            return
        used = set()
        for index, char in enumerate(rest):
            if char in used:
                continue
            used.add(char)
            choose(prefix + char, rest[:index] + rest[index + 1:])

    choose('', text)
    return answer


assert permutations('aab') == ['aab', 'aba', 'baa']

🔗 这一章连到哪里

去哪 为什么
不靠数据的 AI 14 · 回溯与约束传播 ⭐ 同一个回溯骨架换个用途:那一章拿它解约束满足问题,并且往上加了两件本章没有的东西 —— 前向检查「看一步就知道前面有墙」、弧相容「还没走就知道整片区域是墙」

🛑 可以停在这里

回溯题写不出来时,检查有没有成对出现:标记/还原、加入/移除、选择/撤销。


✅ 检查点

矩阵路径题为什么必须恢复 board[r][c]?

👀 看答案

这个格子只是当前分支不能再用;别的起点或兄弟分支仍应可以用它。恢复现场才能让下一条路独立尝试。


⚡ 走神救援

继续: 07 · 位运算与模拟:把规则拆成小动作

打卡记录保存在你的浏览器里,首页能看到总进度