排列问题在前文 [回溯算法核心框架]讲过,这里就简单过一下。
力扣第 46 题「全排列」就是标准的排列问题:
给定一个不含重复数字的数组 nums
,返回其所有可能的全排列。
函数签名如下:
List<List<Integer>> permute(int[] nums)
比如输入 nums = [1,2,3]
,函数的返回值应该是:
[
[1,2,3],[1,3,2],
[2,1,3],[2,3,1],
[3,1,2],[3,2,1]
]
刚才讲的组合/子集问题使用 start
变量保证元素 nums[start]
之后只会出现 nums[start+1..]
中的元素,通过固定元素的相对位置保证不出现重复的子集。
但排列问题本身就是让你穷举元素的位置,nums[i]
之后也可以出现 nums[i]
左边的元素,所以之前的那一套玩不转了,需要额外使用 used
数组来标记哪些元素还可以被选择。
标准全排列可以抽象成如下这棵多叉树:
我们用 used
数组标记已经在路径上的元素避免重复选择,然后收集所有叶子节点上的值,就是所有全排列的结果:
回溯算法秒杀所有排列-组合-子集问题 | labuladong 的算法笔记
这样,全排列问题就解决了。
但如果题目不让你算全排列,而是让你算元素个数为 k
的排列,怎么算?
也很简单,改下 backtrack
函数的 base case,仅收集第 k
层的节点值即可: