当前位置: 首页 > article >正文

Leetcode-100 回溯法-全排列

全排列问题

题目描述

给定一个不含重复数字的整数数组 nums,返回其所有可能的全排列。

示例:

输入: nums = [1,2,3]
输出: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

解题思路

本解法采用 基于交换的回溯法,通过 原地交换数组元素 生成排列,而不是使用额外的空间存储路径。这种方法的核心思想是 通过递归不断交换数组中的元素,最终生成所有可能的排列


算法步骤

  1. 初始化结果列表:创建一个空列表 res 来存储所有排列结果。
  2. 定义递归函数 backtrack(start)
    • 终止条件:当 start == len(nums),说明排列完成,添加当前 nums 到结果集中。
    • 交换操作:遍历 nums 的每个元素,与 start 位置的元素交换,以固定当前位置的数。
    • 递归深入:调用 backtrack(start + 1) 处理下一个位置的元素。
    • 状态回溯:恢复交换前的数组状态,以进行后续排列的生成。
  3. 启动递归:调用 backtrack(0) 开始处理。

代码实现

from typing import List

def permute(nums: List[int]) -> List[List[int]]:
    res = []  # 存放所有排列结果

    def backtrack(start):
        if start == len(nums):  # 终止条件
            res.append(nums[:])  # 复制当前排列结果
            return
        for i in range(start, len(nums)):  
            nums[start], nums[i] = nums[i], nums[start]  # 交换元素
            backtrack(start + 1)  # 递归处理下一个位置
            nums[start], nums[i] = nums[i], nums[start]  # 回溯(恢复原状态)

    backtrack(0)  # 开始回溯
    return res

# 测试
print(permute([1, 2, 3]))

递归的搜索树模型

在回溯法(Backtracking)和递归算法中,我们可以将 递归过程抽象为一棵搜索树

在这里插入图片描述

  • 根节点到叶子节点代表“递归深入”(纵向生长)

    • 每进入递归的下一层,相当于深入到搜索树的下一层。
    • 例如:在 全排列问题 中,每一层固定一个元素,递归进入下一层。
  • 同一层的不同分支代表“遍历当前层的所有可能”(横向生长)

    • 在当前层的 for 循环,遍历所有可能的选择,相当于当前节点的多个分支。
    • 例如:在 子集问题 中,每一层都会尝试不同的元素加入子集。

流程示例

nums = [1,2,3] 为例,演示递归过程:

  1. 固定第 0 位:

    • 交换 11[1,2,3]
    • 递归进入第 1 位:
  2. 固定第 1 位:

    • 交换 22[1,2,3]
    • 递归进入第 2 位:
      • 交换 33[1,2,3] (排列完成,加入结果)
      • 回溯恢复 [1,2,3]
    • 交换 23[1,3,2] (新排列)
    • 递归进入第 2 位:
      • 交换 22[1,3,2] (排列完成,加入结果)
      • 回溯恢复 [1,2,3]
  3. 交换 12[2,1,3],继续递归

    • 重复上述过程,生成所有排列

复杂度分析

  • 时间复杂度:O(N!)

    • 共有 N! 种不同的排列,每种排列的生成过程需要 O(N)次操作,因此整体复杂度为 O(N!)。
  • 空间复杂度:O(N)

    • 递归调用的最大深度为 N ,即递归栈的最大开销,因此空间复杂度为 O(N) (不计算返回结果占用的额外空间)。

http://www.kler.cn/a/592939.html

相关文章:

  • 实用工具-Another Redis Desktop Manager介绍
  • 2023南京理工大学计算机复试上机真题
  • 安全基线-rm命令防护
  • 【论文阅读】Adversarial Patch Attacks on Monocular Depth Estimation Networks
  • 【总结】Pytest vs Behave,BDD 测试框架哪家强?
  • MyBatis 配置文件解析使用了哪些设计模式
  • Hessian 矩阵是什么
  • Quartus + VScode 实现模块化流水灯
  • MySQL-单表查询
  • Java 大视界 -- 基于 Java 的大数据分布式存储系统的数据备份与恢复策略(139)
  • 如何在electron中注册快捷键?
  • 【机器学习】强化学习
  • securtiy_crt访问ubuntu报Key exchange failed问题
  • PostgreSQL 视图
  • AI训练如何获取海量数据,论平台的重要性
  • Python实现WYY音乐下载
  • Redis复制(replica)主从模式
  • 【CMake指南】第12篇:CMake Unity Build 详解
  • Leetcode Hot 100 79.单词搜索
  • 如何把master迁出的bug修改分支,合并、删除本地、删除远端