给定一个不含重复数字的数组 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]]
示例 3:

输入:nums = [1]
输出:[[1]]

预备知识
回溯法:一种通过探索所有可能的候选解来找出所有的解的算法。如果候选解被确认不是一个解(或者至少不是最后一个解),回溯算法会通过在上一步进行一些变化抛弃该解,即回溯并且再次尝试。
方法一:回溯
思路和算法

这个问题可以看作有 n 个排列成一行的空格,我们需要从左往右依此填入题目给定的 nn 个数,每个数只能使用一次。那么很直接的可以想到一种穷举的算法,即从左往右每一个位置都依此尝试填入一个数,看能不能填完这 nn 个空格,在程序中我们可以用「回溯法」来模拟这个过程。

我们定义递归函数 backtrack(first, output) 表示从左往右填到第 \textit{first}first 个位置,当前排列为 \textit{output}output。 那么整个递归函数分为两个情况:

如果 ,说明我们已经填完了 n 个位置(注意下标从 0 开始),找到了一个可行的解,我们将 \textit{output}output 放入答案数组中,递归结束。
如果 \textit{first}<nfirst<n,我们要考虑这第 \textit{first}first 个位置我们要填哪个数。根据题目要求我们肯定不能填已经填过的数,因此很容易想到的一个处理手段是我们定义一个标记数组 \textit{vis}[]vis[] 来标记已经填过的数,那么在填第 \textit{first}first 个数的时候我们遍历题目给定的 nn 个数,如果这个数没有被标记过,我们就尝试填入,并将其标记,继续尝试填下一个位置,即调用函数 backtrack(first + 1, output)。回溯的时候要撤销这一个位置填的数以及标记,并继续尝试其他没被标记过的数。
使用标记数组来处理填过的数是一个很直观的思路,但是可不可以去掉这个标记数组呢?毕竟标记数组也增加了我们算法的空间复杂度。

答案是可以的,我们可以将题目给定的 nn 个数的数组 \textit{nums}nums 划分成左右两个部分,左边的表示已经填过的数,右边表示待填的数,我们在回溯的时候只要动态维护这个数组即可。

具体来说,假设我们已经填到第 \textit{first}first 个位置,那么 \textit{nums}nums 数组中 [0,\textit{first}-1][0,first−1] 是已填过的数的集合,[\textit{first},n-1][first,n−1] 是待填的数的集合。我们肯定是尝试用 [\textit{first},n-1][first,n−1] 里的数去填第 \textit{first}first 个数,假设待填的数的下标为 ii ,那么填完以后我们将第 ii 个数和第 \textit{first}first 个数交换,即能使得在填第 \textit{first}+1first+1个数的时候 \textit{nums}nums 数组的[0,first][0,first] 部分为已填过的数,[\textit{first}+1,n-1][first+1,n−1] 为待填的数,回溯的时候交换回来即能完成撤销操作。

举个简单的例子,假设我们有 [2, 5, 8, 9, 10] 这 5 个数要填入,已经填到第 3 个位置,已经填了 [8,9] 两个数,那么这个数组目前为 [8, 9 | 2, 5, 10] 这样的状态,分隔符区分了左右两个部分。假设这个位置我们要填 10 这个数,为了维护数组,我们将 2 和 10 交换,即能使得数组继续保持分隔符左边的数已经填过,右边的待填 [8, 9, 10 | 2, 5] 。

当然善于思考的读者肯定已经发现这样生成的全排列并不是按字典序存储在答案数组中的,如果题目要求按字典序输出,那么请还是用标记数组或者其他方法。

下面的图展示了回溯的整个过程:

class Solution:def permute(self, nums):""":type nums: List[int]:rtype: List[List[int]]"""def backtrack(first = 0):# 所有数都填完了if first == n:  res.append(nums[:])for i in range(first, n):# 动态维护数组nums[first], nums[i] = nums[i], nums[first]# 继续递归填下一个数backtrack(first + 1)# 撤销操作nums[first], nums[i] = nums[i], nums[first]n = len(nums)res = []backtrack()return res
class Solution:def permute(self,nums):def backtrack(first ==0):if first ==n:res.append(nums[:])for i in range(first,n):nums[first],nums[i] = nums[i],nums[first]backtrack(fist+1)nums[first],nums[i] = nums[i],nums[first]n=len(nums)res=[]backtrack()return res
class Solution:def permute(self, nums):def backtrack(first =0):if first ==n:res.append(nums[:]):for i in range(first,n):nums[first],nums[i]=nums[i],nums[first]backtrack(first+1)nums[first],nums[i] = nums[i],nums[first]n = len(nums)res =[]backtrack()return res
class Soluton:def permute(self,nums):def backtrack(first=0):if first ==n:res.append(nums[:])for i in range(first,n):nums[first],nums[i] = nums[i],nums[first]backtrack(first +1)nums[first],nums[i] = nums[i],nums[first]n = len(nums)res =[]backtrack()return res
class Solution:def permute(self,nums):def backtrack(first =0):if first ==n:res.append(nums[:])for i in range(first,n):nums[first],nums[i]=nums[i],nums[first]backtrack(first+1)nums[first],nums[i] = nums[i],nums[first]n = len(nums)res =[]backtrack()return res

2021-09-08 全排列相关推荐

  1. 【Leetcode】每日一题2021/09/08

    这道题前面做过 class Solution {public String replaceSpace(String s) {String res = new String();int len = s. ...

  2. 橘子CPS联盟操作手册2021.09

    橘子CPS联盟操作手册2021.09 目录 橘子CPS联盟操作手册2021.09 橘子CPS联盟是干嘛的 橘子CPS基本操作流程 PC端操作 1.注册 2.登陆 3.渠道管理 4.分享网站 5.分享网 ...

  3. 【Flutter】Flutter 开发环境搭建 ( 2021年08月25日 补充最新资料 | 最新安装教程 )

    文章目录 前言 一.Android Studio 环境安装 Flutter / Dart 插件 二.Flutter SDK 下载 三.设置 Flutter 环境变量 1.设置 Flutter SDK环 ...

  4. 2021.09.27 MySQL笔记

    2021.09.27 MySQL笔记 文章目录 2021.09.27 MySQL笔记 一.展示当前存在的所有数据库 二.使用(选中)一个数据库 三.创建一个数据表 四.查询并展示该数据库内的所有数据表 ...

  5. 实习日志 (2021.09.13)

    2021.09.13星期一 今天把之前的算法题终于给弄明白了,并能够按照自己的思路去把他给完成,总结这个题目并不是很难,最重要的是要把链表给弄懂,一开始由于我对链表不是很熟悉,导致我在写该题目的时候花 ...

  6. 2021.09青少年软件编程(Python)等级考试试卷(三级)

    2021.09青少年软件编程(Python)等级考试试卷(三级) 一.单选题(共25题,每题2分,共50分) 1.使用map函数可以实现列表数据元素类型的转换,而无需通过循环.则将列表L=['1',' ...

  7. 2021.04.08 线程和进程的使用

    2021.04.08 线程和进程的作用 直接通过Thread创建子线程 Thread(target=需要在子线程中调用的函数,args=(函数的实参列表)) from threading import ...

  8. 2021.09.24—皮皮与帅帅的第二篇情话

    2021.09.24我们小情书的第二天 每天晚上,小兔子都会一个人来到溪水边,坐在地上数着星星.而且他个人也非常喜欢一闪一闪的东西.对于小兔子来说,每颗星星都是特别的,于是她就给每颗星星都起了一个可爱 ...

  9. 电大计算机网考怎么过,史上最牛--电大计算机网考小抄(考试必备)--2016.09.08【呕心沥血整理、电大考试必过】.doc...

    史上最牛--电大计算机网考小抄(考试必备)--2016.09.08[呕心沥血整理.电大考试必过] 计算机网考Windows操作系统及其应用-选择题B A.Ctrl + Alt B.Ctrl + Shi ...

  10. 《惢客创业日记》2021.09.15(周三)套路的最高境界

    今天,凉粉儿给我发了一段她想的关于惢客的宣传词:"你被套路过吗?想不再被套路吗?上惢客."总结一句话是"不被套路上惢客".我觉得能把惢客跟套路联系在一起,很贴切 ...

最新文章

  1. ML之Kmeans:利用自定义Kmeans函数实现对多个坐标点(自定义四个点)进行自动(最多迭代10次)分类
  2. Java Graphics2D类的绘图方法
  3. tl_war302虚拟服务器,tl-war302设置教程
  4. python读取文件每行_python – 在文本文件中的每4行读取,编辑和写入
  5. leaving target processor paused”错误怎么解决
  6. java spring 登录验证_浅析Spring Security登录验证流程源码
  7. python两个 list 获取交集,并集,差集的方法
  8. Flat UI Colors——扁平化配色参考
  9. HGO工具CoordTool坐标七参数转换
  10. 宾馆管理c语言程序报告,C语言课程设计-宾馆客房管理系统报告.docx
  11. WIN10网络打印机-打印失败解决方案
  12. Linux之美—windows server基础(在windows上安装server机)
  13. OpenVR学习01 成功打开了VR设备
  14. BOOST升压电路参数计算
  15. PLC中ST语言的几种程序流程控制语句
  16. 图书馆管理系统课程设计
  17. 超快速安装Mac上的Homebrow,解决homebrow安装错误curl: (35) LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to
  18. 【带着canvas去流浪(9)】粒子动画
  19. 12333新农合网上查询_12333新农合查询网站 农村医疗保险缴费查询
  20. 出国不用兑换美元啦 细说人民币跨境支付系统的幕后功臣

热门文章

  1. php v9搜索不到内容,關於如何解決PHPCMS V9內容搜索顯示不全問題解決方案
  2. sharding技术
  3. Hibernate注解与JPA
  4. 使用USB直接方式解决ESXi识别加密狗的问题
  5. phpstorm常用功能快捷键(mac)
  6. java集合学习笔记--二维集合HashMap
  7. 关于Jquery ajax调用一般处理程序Handler报500 错误(Internal Server Error)解决办法
  8. linq to sql 系列之 linq to sql性能优化技巧
  9. ThinkPHP视图模型实例
  10. hutool 获取某月最后一天_Hutool之时间工具——DateUtil