46.全排列
😍46.全排列
给定一个 没有重复数字的序列,返回其所有可能的全排列。
示例
示例:
- 输入: [1,2,3]
- 输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]
思路
基本想法
拿[1,2,3]举例,首先从1开始,先取2,再取3,形成[1,2,3],之后取3,再去2,形成[1,3,2],
之后从2开始,取1,3形成[2,1,3],取3,1形成[2,3,1],最后从3开始,对剩下两个元素进行排列
总结来说就是取一个元素,再对剩下的元素进行全排列,依次取遍集合中的所有元素,剩下的元素全排列即可。
对于剩下的元素是一样的处理逻辑,从剩下的元素中取一个,依次取遍剩余集合中的所有元素,每次取一个剩下的元素,形成一个更小的集合。。。
由此形成一个搜索树:
相对于组合来说,排列可以每次都从头开始取元素,但是上层已经使用过的元素不能再用
执行流程
从之前的子集问题思路开始,确定递归结束的条件,for
循环的范围
递归结束的条件:由于是全排列,所以当
path
中的元素个数等于nums
中的元素个数时就形成了一个全排列,此时加入res
结果集中并进行返回for
循环的范围:由于每次取一个元素,再把剩下的元素进行全排列,所以不能简单的通过for
循环的范围进行限制,而是需要使用一个标志记录当前哪个元素被使用并且由于需要进行多层递归,所以只能使用一个标志数组来记录每一层被使用过的元素
剩下的过程与子集问题完全一样
代码
|
|
总结
在子集的基础上放开限制,[1,2]和[2,1]在排列问题中是不一样的,在子集问题中是一样的,除了此处不同,在for循环判断条件上也有不同,子集问题有一个startIndex
,而排列问题每次都是遍历整个集合,使用一个标志数组来记录哪些元素被使用过,所以在回溯时,不仅仅时path.pop_back()
,还有flag[i]=false
。
每一次从当前元素重新出发,但是需要注意的是,已经遍历过的元素不能再遍历了