python 3种算法 回溯法、字典序生成、递归交换 实现全排列【力扣46题】

简介: python 3种算法 回溯法、字典序生成、递归交换 实现全排列【力扣46题】

作者介绍:10年大厂数据\经营分析经验,现任大厂数据部门负责人。

会一些的技术:数据分析、算法、SQL、大数据相关、python

欢迎加入社区:码上找工作

作者专栏每日更新:

LeetCode解锁1000题: 打怪升级之旅

python数据分析可视化:企业实战案例

备注说明:方便大家阅读,统一使用python,带必要注释,公众号 数据分析螺丝钉 一起打怪升级

题目描述

给定一个不含重复数字的数组 nums,返回其所有可能的全排列。你可以以任意顺序返回答案。

输入格式
  • nums:一个整数数组。
输出格式
  • 返回一个列表,包含所有可能的排列。
示例
示例 1
输入: nums = [1,2,3]
输出: [[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1]]
示例 2
输入: nums = [0,1]
输出: [[0,1], [1,0]]

方法一:回溯算法

解题步骤
  1. 初始化:创建一个空列表 res 来存储所有排列结果。
  2. 递归函数:编写一个递归函数,使用当前序列 path 和选择列表 nums 来生成排列。
  3. 结束条件:如果 path 的长度等于 nums 的长度,则将 path 添加到结果列表 res 中。
  4. 循环选择:遍历 nums 中的每个数字,如果数字未被选择,则加入到 path,并继续递归,最后撤销选择。
完整代码
def permute(nums):
    """
    使用回溯算法生成数组的全排列
    :param nums: List[int], 输入的整数数组
    :return: List[List[int]], 所有可能的全排列
    """
    def backtrack(path, options):
        # 如果当前路径的长度等于输入数组的长度,说明找到了一种排列
        if len(path) == len(nums):
            res.append(path[:])
            return
        
        # 遍历当前可选择的数字
        for i in range(len(options)):
            # 选择当前数字
            path.append(options[i])
            # 继续递归填下一个数
            backtrack(path, options[:i] + options[i+1:])
            # 撤销选择
            path.pop()
    res = []
    backtrack([], nums)
    return res
# 示例调用
print(permute([1, 2, 3]))  # 输出: [[1, 2, 3], [1, 3, 2], ..., [3, 2, 1]]
算法分析
  • 时间复杂度:(O(n! \times n)),生成所有排列需要 (n!) 次调用,每次调用处理列表需要 (O(n)) 时间。
  • 空间复杂度:(O(n)),递归深度为 (n),使用了额外的空间存储当前排列。

方法二:字典序生成算法

解题步骤
  1. 排序:先将数组排序。
  2. 查找:从右向左查找第一个升序的相邻元素对 (i, j),即 nums[i] < nums[j]
  3. 交换与反转:如果找到,再从右向左查找第一个大于 nums[i] 的元素 nums[k],交换 nums[i]nums[k],然后反转 i+1 到末尾的元素。
  4. 重复:重复以上步骤直到完全逆序。
完整代码
def permute(nums):
    """
    使用字典序算法生成数组的全排列
    :param nums: List[int], 输入的整数数组
    :return: List[List[int]], 所有可能的全排列
    """
    def next_permutation(perm):
        # 找到升序的边界
        i = len(perm) - 2
        while i >= 0 and perm[i] >= perm[i + 1]:
            i -= 1
        if i == -1:
            return False
        
        # 找到需要交换的位置
        j = len(perm) - 1        while perm[j] <= perm[i]:
            j -= 1
        perm[i], perm[j] = perm[j], perm[i]
        
        # 反转i后面的部分
        perm[i + 1:] = perm[i + 1:][::-1]
        return True
    
    nums.sort()
    res = [nums[:]]
    while next_permutation(nums):
        res.append(nums[:])
    return res
# 示例调用
print(permute([1, 2, 3]))  # 输出: [[1, 2, 3], [1, 3, 2], ..., [3, 2, 1]]
算法分析
  • 时间复杂度:(O(n! ✖️ n)),尽管每次生成下一个排列只需要 (O(n)) 时间,但总共有 (n!) 个排列。
  • 空间复杂度:(O(1)),除了输出数组外,空间使用是常数。

方法三:递归交换

解题步骤
  1. 递归函数定义:定义一个递归函数,使用当前索引 start 来处理排列。
  2. 递归终止条件:如果 start 等于数组长度,记录当前排列。
  3. 递归交换:从 start 开始,将每个元素交换到 start 位置,然后递归处理 start + 1
完整代码
def permute(nums):
    """
    使用递归交换方法生成数组的全排列
    :param nums: List[int], 输入的整数数组
    :return: List[List[int]], 所有可能的全排列
    """
    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]
    res = []
    backtrack(0)
    return res
# 示例调用
print(permute([1, 2, 3]))  # 输出: [[1, 2, 3], [1, 3, 2], ..., [3, 2, 1]]
算法分析
  • 时间复杂度:(O(n! ✖️ n)),需要进行 (n!) 次调用,每次调用中进行的操作与 (n) 成正比。
  • 空间复杂度:(O(n)),递归深度最大为 (n),使用了额外的空间存储当前排列状态。

总结

为了直观地比较解决LeetCode题目46 "全排列"的三种方法,下面的表格将展示它们在不同技术维度的性能和特点,包括时间复杂度、空间复杂度以及各自的优势和劣势。

特征 方法一:回溯算法 方法二:字典序算法 方法三:递归交换法
时间复杂度 (O(n! \times n)) (O(n! \times n)) (O(n! \times n))
空间复杂度 (O(n)) (O(1)) (O(n))
优势 - 灵活且直观
- 易于实现和理解
- 非递归,避免栈溢出
- 效率高于普通回溯
- 实现简单
- 直接在输入数组上操作
劣势 - 空间消耗较大
- 深度递归可能导致栈溢出
- 实现复杂度较高
- 不如回溯直观
- 多次交换操作复杂
- 递归依旧可能栈溢出
适用场景 - 需要所有可能解时
- 教学和基础算法学习
- 需要按字典顺序生成全排列
- 大规模数据处理
- 内存使用敏感
- 喜欢简洁代码风格

综合分析

方法一(回溯算法)

  • 回溯算法是解决排列、组合问题的经典方法,非常直观,可以灵活地处理各种约束条件。其主要缺点是在深度递归时可能会消耗较多内存,特别是在解空间非常大时。

方法二(字典序算法)

  • 字典序算法提供了一种非递归的解决方案,能够有效地按照字典顺序生成下一个排列,适用于需要顺序输出或者大数据量的问题。然而,这种方法在实现上较为复杂,可能不太直观。

方法三(递归交换法)

  • 递归交换法通过直接在输入数组上进行操作,避免了额外的空间使用,简化了代码的复杂性。但与回溯类似,它的缺点是递归深度大时仍可能导致栈溢出问题,且多次交换操作可能相对复杂。

在选择合适的方法时,可以根据具体问题的需求、可用资源以及开发时间来做决策。例如,对于教学或基础学习,推荐使用回溯算法;对于工业级应用,考虑字典序算法;而对于内存敏感或喜欢简洁代码的场景,递归交换法可能是一个好选择。


欢迎关注微信公众号 数据分析螺丝钉

相关文章
|
1月前
|
机器学习/深度学习 存储 算法
解锁文件共享软件背后基于 Python 的二叉搜索树算法密码
文件共享软件在数字化时代扮演着连接全球用户、促进知识与数据交流的重要角色。二叉搜索树作为一种高效的数据结构,通过有序存储和快速检索文件,极大提升了文件共享平台的性能。它依据文件名或时间戳等关键属性排序,支持高效插入、删除和查找操作,显著优化用户体验。本文还展示了用Python实现的简单二叉搜索树代码,帮助理解其工作原理,并展望了该算法在分布式计算和机器学习领域的未来应用前景。
|
2月前
|
监控 算法 安全
深度洞察内网监控电脑:基于Python的流量分析算法
在当今数字化环境中,内网监控电脑作为“守城卫士”,通过流量分析算法确保内网安全、稳定运行。基于Python的流量分析算法,利用`scapy`等工具捕获和解析数据包,提取关键信息,区分正常与异常流量。结合机器学习和可视化技术,进一步提升内网监控的精准性和效率,助力企业防范潜在威胁,保障业务顺畅。本文深入探讨了Python在内网监控中的应用,展示了其实战代码及未来发展方向。
|
2月前
|
机器学习/深度学习 人工智能 算法
基于Python深度学习的眼疾识别系统实现~人工智能+卷积网络算法
眼疾识别系统,本系统使用Python作为主要开发语言,基于TensorFlow搭建卷积神经网络算法,并收集了4种常见的眼疾图像数据集(白内障、糖尿病性视网膜病变、青光眼和正常眼睛) 再使用通过搭建的算法模型对数据集进行训练得到一个识别精度较高的模型,然后保存为为本地h5格式文件。最后使用Django框架搭建了一个Web网页平台可视化操作界面,实现用户上传一张眼疾图片识别其名称。
213 5
基于Python深度学习的眼疾识别系统实现~人工智能+卷积网络算法
|
16天前
|
存储 算法 Java
算法系列之递归反转单链表
递归反转链表的基本思路是将当前节点的next指针指向前一个节点,然后递归地对下一个节点进行同样的操作。递归的核心思想是将问题分解为更小的子问题,直到达到基本情况(通常是链表末尾)。
34 5
算法系列之递归反转单链表
|
2天前
|
存储 算法 文件存储
探秘文件共享服务之哈希表助力 Python 算法实现
在数字化时代,文件共享服务不可或缺。哈希表(散列表)通过键值对存储数据,利用哈希函数将键映射到特定位置,极大提升文件上传、下载和搜索效率。例如,在大型文件共享平台中,文件名等信息作为键,物理地址作为值存入哈希表,用户检索时快速定位文件,减少遍历时间。此外,哈希表还用于文件一致性校验,确保传输文件未被篡改。以Python代码示例展示基于哈希表的文件索引实现,模拟文件共享服务的文件索引构建与检索功能。哈希表及其分布式变体如一致性哈希算法,保障文件均匀分布和负载均衡,持续优化文件共享服务性能。
|
8天前
|
监控 算法 安全
公司电脑网络监控场景下 Python 广度优先搜索算法的深度剖析
在数字化办公时代,公司电脑网络监控至关重要。广度优先搜索(BFS)算法在构建网络拓扑、检测安全威胁和优化资源分配方面发挥重要作用。通过Python代码示例展示其应用流程,助力企业提升网络安全与效率。未来,更多创新算法将融入该领域,保障企业数字化发展。
34 10
|
9天前
|
监控 算法 安全
基于 Python 广度优先搜索算法的监控局域网电脑研究
随着局域网规模扩大,企业对高效监控计算机的需求增加。广度优先搜索(BFS)算法凭借其层次化遍历特性,在Python中可用于实现局域网内的计算机设备信息收集、网络连接状态监测及安全漏洞扫描,确保网络安全与稳定运行。通过合理选择数据结构与算法,BFS显著提升了监控效能,助力企业实现智能化的网络管理。
24 7
|
25天前
|
算法 Serverless 数据处理
从集思录可转债数据探秘:Python与C++实现的移动平均算法应用
本文探讨了如何利用移动平均算法分析集思录提供的可转债数据,帮助投资者把握价格趋势。通过Python和C++两种编程语言实现简单移动平均(SMA),展示了数据处理的具体方法。Python代码借助`pandas`库轻松计算5日SMA,而C++代码则通过高效的数据处理展示了SMA的计算过程。集思录平台提供了详尽且及时的可转债数据,助力投资者结合算法与社区讨论,做出更明智的投资决策。掌握这些工具和技术,有助于在复杂多变的金融市场中挖掘更多价值。
47 12
|
23天前
|
算法 安全 网络安全
基于 Python 的布隆过滤器算法在内网行为管理中的应用探究
在复杂多变的网络环境中,内网行为管理至关重要。本文介绍布隆过滤器(Bloom Filter),一种高效的空间节省型概率数据结构,用于判断元素是否存在于集合中。通过多个哈希函数映射到位数组,实现快速访问控制。Python代码示例展示了如何构建和使用布隆过滤器,有效提升企业内网安全性和资源管理效率。
50 9
|
1月前
|
监控 算法 安全
内网桌面监控软件深度解析:基于 Python 实现的 K-Means 算法研究
内网桌面监控软件通过实时监测员工操作,保障企业信息安全并提升效率。本文深入探讨K-Means聚类算法在该软件中的应用,解析其原理与实现。K-Means通过迭代更新簇中心,将数据划分为K个簇类,适用于行为分析、异常检测、资源优化及安全威胁识别等场景。文中提供了Python代码示例,展示如何实现K-Means算法,并模拟内网监控数据进行聚类分析。
43 10