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) - 2while i >= 0 and perm[i] >= perm[i + 1]:i -= 1if i == -1:return False# 找到需要交换的位置j = len(perm) - 1        while perm[j] <= perm[i]:j -= 1perm[i], perm[j] = perm[j], perm[i]# 反转i后面的部分perm[i + 1:] = perm[i + 1:][::-1]return Truenums.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[:])returnfor 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))
优势- 灵活且直观
- 易于实现和理解
- 非递归,避免栈溢出
- 效率高于普通回溯
- 实现简单
- 直接在输入数组上操作
劣势- 空间消耗较大
- 深度递归可能导致栈溢出
- 实现复杂度较高
- 不如回溯直观
- 多次交换操作复杂
- 递归依旧可能栈溢出
适用场景- 需要所有可能解时
- 教学和基础算法学习
- 需要按字典顺序生成全排列
- 大规模数据处理
- 内存使用敏感
- 喜欢简洁代码风格

综合分析

方法一(回溯算法)

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

方法二(字典序算法)

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

方法三(递归交换法)

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/915.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

webpack 打包优化 - splitChunks

打包时会遇到的问题&#xff1a; 打包文件过大&#xff0c;首屏加载时间过长&#xff0c;js阻塞页面渲染导致白屏改动业务代码后&#xff0c;对于第三方库也会一并重新打包到一个出口文件&#xff0c;浏览器无法利用缓存来减少请求和加载的时间 针对以上两个问题&#xff0c;…

适合生产制造企业用的ERP系统有哪些?

适合生产制造企业用的ERP系统有哪些&#xff1f; 想选择适合生产制造企业的ERP&#xff0c;首先了解市面上有哪些ERP系统 市面上的ERP系统主要分为三大类&#xff1a; 1、垂直领域的ERP系统&#xff1a;这些系统是针对特定行业或垂直市场定制的ERP解决方案&#xff0c;通常具…

功能测试前景揭秘:会被淘汰吗?

在当今快速发展的信息时代&#xff0c;软件已经成为我们工作、学习乃至生活中不可或缺的一部分。随着技术的不断进步和应用的广泛普及&#xff0c;软件测试作为保障软件质量和功能实现的关键步骤&#xff0c;其职业发展路径也受到了广泛的关注。特别是针对功能测试这一细分领域…

我与C++的爱恋:隐式类型转换

​ ​ &#x1f525;个人主页&#xff1a;guoguoqiang. &#x1f525;专栏&#xff1a;我与C的爱恋 朋友们大家好&#xff0c;本篇内容我们来介绍初始化列表&#xff0c;隐式类型转换以及explicit的内容 一、初始化列表 1.1 构造函数体赋值 在创建对象时&#xff0c;编译器…

说说redis的数据类型

1.字符串&#xff08;String&#xff09;&#xff1a;其存储二进制的数据&#xff0c;对数据可以进行原子性的增加或者减少操作 2.List&#xff08;列表&#xff09;&#xff1a;按照插入顺序进行排序&#xff0c;可以进行元素的重复&#xff0c;可以对列表的两端进行插入或者删…

etcd campaign

1. 引言 本文主要讲解使用etcd进行选举的流程&#xff0c;以及对应的缺陷和使用场景 2. etcd选举流程 流程如以代码所示&#xff0c;流程为&#xff1a; clientv3.New 创建client与etcd server建立连接 concurrency.NewSession 创建选举的session&#xff0c;一般会配置ses…

java:Java中的接口

什么是接口 概念&#xff1a; 官方解释&#xff1a;Java接口是一系列方法的声明&#xff0c;是一些方法特征的集合&#xff0c;一个接口只有方法的特征没有方法的实现&#xff0c;因此这些方法可以在不同的地方被不同的类实现&#xff0c;而这些实现可以具有不同的行为&#x…

Java Maven项目推送到 Maven 中央仓库

准备阶段 namespace 域名认证 当需要在 sonatype 认证 com.xxx命名空间时&#xff0c;需要将 .xxx.com 配置域名解析。 记录类型&#xff1a;TXT 文本内容&#xff1a;验证的 key。 GPG 公私钥生成 GPG 下载地址&#xff1a;https://www.gnupg.org/download/index.html M…

零代码编程:用kimichat将mp4视频批量转为mp3音频

一个文件夹里面有多个子文件夹&#xff0c;里面的视频需要转成为mp3音频格式。可以在kimichat中键入提示词&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个Python脚本的编写任务&#xff0c;具体步骤如下&#xff1a; 打开文件夹&#xff1a;D:\CHATGPT For TikT…

openAI介绍及相关概念

OpenAI 简介 成立背景: OpenAI 成立于 2015 年&#xff0c;由一群高科技界的重要人物创立&#xff0c;包括 Elon Musk 和 Sam Altman。其目标是推动人工智能&#xff08;AI&#xff09;的发展&#xff0c;同时确保 AI 的发展能够造福全人类。 研究方向: OpenAI 专注于深度学习…

新手必犯的十大错误 Python语言

Python 是一种广泛使用的编程语言&#xff0c;它以其简洁和易读性而闻名。然而&#xff0c;即使是经验丰富的程序员也可能会遇到一些常见的错误。以下是一些常见的 Python 错误案例&#xff1a; 语法错误&#xff08;SyntaxError&#xff09;&#xff1a; print("Hello Wo…

SpringBoot中异步执行事务REQUIRED和REQUIRED_NEW的区别

springboot中事务的使用方式 在spring的bean中&#xff0c;要开启数据库事务只需要在方法中标注注解 Transactional 注解常用的参数有 Class[] rollbackFor() default {} 指定回滚异常Propagation propagation() default Propagation.REQUIRED 事务的传播机制Isolation iso…

Hive:GROUP BY GROUPING SETS

分组聚合 group by x1, x2, x3 grouping sets((x1), (x1, x2), (x1, x3),(x1, x2, x3)) 将不同维度的GROUP BY结果进行UNION ALL操作 GROUPING SETS会把在单个GROUP BY逻辑中没有参与GROUP BY的那一列置为NULL值&#xff0c;这样聚合出来的结果&#xff0c;未被GROUP BY的列…

web server apache tomcat11-10-Class Loader

前言 整理这个官方翻译的系列&#xff0c;原因是网上大部分的 tomcat 版本比较旧&#xff0c;此版本为 v11 最新的版本。 开源项目 从零手写实现 tomcat minicat 别称【嗅虎】心有猛虎&#xff0c;轻嗅蔷薇。 系列文章 web server apache tomcat11-01-官方文档入门介绍 web…

AI推介-多模态视觉语言模型VLMs论文速览(arXiv方向):2024.04.10-2024.04.15

文章目录~ 1.Photo-Realistic Image Restoration in the Wild with Controlled Vision-Language Models2.Do LLMs Understand Visual Anomalies? Uncovering LLM Capabilities in Zero-shot Anomaly Detection3.UNIAA: A Unified Multi-modal Image Aesthetic Assessment Base…

大华相机C#学习之Enumerator类

构造函数 Enumerator() 创建一个Enumerator实例。 常用方法 EnumerateDevices() 枚举所有发现设备,返回List<IDeviceInfo>对象。 List<IDeviceInfo> devices new List<IDeviceInfo>();private void test_Click(object sender, EventArgs e) {devicesEnum…

【Spring进阶】基于注解的面向切面编程(AOP)详解

hi&#xff0c;我是程序员王也&#xff0c;一个资深Java开发工程师&#xff0c;平时十分热衷于技术副业变现和各种搞钱项目的程序员~&#xff0c;如果你也是&#xff0c;可以一起交流交流。 今天我们聊一聊Spring中的AOP~ AOP的核心概念 面向切面编程&#xff08;AOP&#xff…

如何实现redis的高可用?

1.主从模式&#xff1a;就是一个住节点&#xff0c;多个从节点&#xff0c;但是弊端是一个主节点崩了&#xff0c;需要手动的切换从节点&#xff0c;这个挺麻烦的 2.哨兵模式&#xff1a;就是为了解决主从模式的弊端从而在主从模式的基础上加了哨兵&#xff0c;从而可以实现自动…

【一】ECharts----【基本概念、基本实例】

目录 零.前言 一.ECharts的安装 1.1独立版本的安装 1.2CDN的安装 1.3NPM的安装 二.ECharts实例 三.系列(series) 四.创建一个ECharts图表的基本步骤 4.1创建一个DOM容器 4.2使用DOM节点初始化ECharts对象 4.3设置配置信息 4.3.1图表标题 4.3.2提示信息 4.3.3图例组…

90天玩转Python—18—Python面向对象编程:核心概念详解

90天玩转Python系列文章目录 90天玩转Python—01—基础知识篇:C站最全Python标准库总结 90天玩转Python--02--基础知识篇:初识Python与PyCharm 90天玩转Python—03—基础知识篇:Python和PyCharm(语言特点、学习方法、工具安装) 90天玩转Python—04—基础知识篇:Pytho…