D
AI
学习工作台
算法2026-05-221 分钟阅读

递归与回溯

决策树搜索、剪枝、去重与经典回溯模板

递归回溯DFS剪枝面试记笔记标记疑惑

递归三要素

  • 终止条件:最小子问题直接返回。
  • 递归关系:大问题化为规模更小的同类问题。
  • 返回值与含义:单值、布尔、或路径收集。
  • 斐波那契教学用递归,面试要补记忆化或递推,避免重复子问题爆炸。

    def fib(n, memo=None):
        if memo is None:
            memo = {}
        if n <= 1:
            return n
        if n not in memo:
            memo[n] = fib(n - 1, memo) + fib(n - 2, memo)
        return memo[n]

    回溯通用模板

    决策树的每条从根到叶的路径上,依次做选择:

    def backtrack(path, options):
        if 满足结束条件:
            result.append(path[:])  # 拷贝
            return
        for choice in options:
            if 不合法(choice):
                continue
            path.append(choice)
            更新状态(choice)
            backtrack(path, 下一层选项)
            path.pop()
            恢复状态(choice)

    子集(元素可选可不选):每层从 start 开始枚举,避免重复组合。

    def subsets(nums):
        res, path = [], []
    

    def dfs(start): res.append(path[:]) for i in range(start, len(nums)): path.append(nums[i]) dfs(i + 1) path.pop()

    dfs(0) return res

    排列、组合与去重

    • 组合 C(n,k)start 只增,保证 [1,2][2,1] 不重复。
    • 排列:需要 used 数组;有重复元素时先排序,同一层 if i > start and nums[i]==nums[i-1]: continue(组合)或 !used[i-1] 规则(排列)。
    N 皇后:按行放皇后,列上检查列、主副对角冲突(用集合或位运算),放不下则剪枝。

    复杂度与面试表达

    回溯最坏常指数级,面试要说清分支因子剪枝效果。答题步骤:画决策树 → 写 path/used → 写终止与收集 → 写剪枝条件 → 提空间为递归深度 O(n)。

    经典题:46、47、78、39、40、51、79(网格 DFS 亦同「四方向回溯」)。网格题注意 visited 与回溯还原,避免重复访问同一格。

    知识卡片

    问题

    回溯与 DFS 的关系?

    点击翻转查看答案

    答案

    回溯是在 DFS 决策树上做「选择 → 递归 → 撤销选择」的模板,显式恢复状态以探索所有分支,常用于组合、排列、划分、棋盘类问题。

    问题

    回溯中「剪枝」指什么?

    点击翻转查看答案

    答案

    在递归前用约束提前 return,避免进入必然无效或更差的子树,例如和已超过 target、剩余元素不够填满等。

    问题

    排列去重为什么要先排序?

    点击翻转查看答案

    答案

    排序后相同元素相邻,用 used 或「同层跳过相同值」规则,避免同一排列被不同分支重复生成。