给定一个 **没有重复** 数字的序列,返回其所有可能的全排列。 **示例:** ```js 输入: [1,2,3] 输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ] ``` 附赠leetcode地址:[leetcode](https://leetcode-cn.com/problems/permutations/solution/quan-pai-lie-wen-ti-by-user7746o/)
Activity
sisterAn commentedon Sep 1, 2020
本题是回溯算法的经典应用场景
1. 算法策略
回溯算法是一种搜索法,试探法,它会在每一步做出选择,一旦发现这个选择无法得到期望结果,就回溯回去,重新做出选择。深度优先搜索利用的就是回溯算法思想。
2. 适用场景
回溯算法很简单,它就是不断的尝试,直到拿到解。它的这种算法思想,使它通常用于解决广度的搜索问题,即从一组可能的解中,选择一个满足要求的解。
3. 代码实现
我们可以写一下,数组 [1, 2, 3] 的全排列有:
即回溯的处理思想,有点类似枚举搜索。我们枚举所有的解,找到满足期望的解。为了有规律地枚举所有可能的解,避免遗漏和重复,我们把问题求解的过程分为多个阶段。每个阶段,我们都会面对一个岔路口,我们先随意选一条路走,当发现这条路走不通的时候(不符合期望的解),就回退到上一个岔路口,另选一种走法继续走。
图片来自于:https://pic.leetcode-cn.com/0bf18f9b86a2542d1f6aa8db6cc45475fce5aa329a07ca02a9357c2ead81eec1-image.png
这显然是一个 递归 结构;
depth,或者命名为index,表示当前要确定的是某个全排列中下标为index的那个数是多少;used[num] = true,这样在考虑下一个位置的时候,就能够以 O(1)的时间复杂度判断这个数是否被选择过,这是一种「以空间换时间」的思想。4. 复杂度分析
时间复杂度: O(n∗n!),其中 n 为序列的长度
这是一个排列组合,每层的排列组合数为:Amn=n!/(n−m)! ,故而所有的排列有 :
A1n + A2n + … + An-1n = n!/(n−1)! + n!/(n−2)! + … + n! = n! * (1/(n−1)! + 1/(n−2)! + … + 1) <= n! * (1 + 1/2 + 1/4 + … + 1/2n-1) < 2 * n!
并且每个内部结点循环 n 次,故非叶子结点的时间复杂度为 O(n∗n!)
空间复杂度:O(n)
leetcode
Jeckhenry commentedon Sep 2, 2020
marlboroKay commentedon Sep 3, 2020
marlboroKay commentedon Sep 3, 2020
题解
1.分析示列,不难发现全排列,首先将每个元素排到第一位。
2.剩余元素再重复第一步操作,依次处理各个元素。
3.通过1,2两步操作,可以利用递归实现操作,但是有个地方需要特别处理,就是对于移动的元素,
在递归操作之前,和之后该如何操作。
4.由此产生两种解决办法,一种是利用回溯,定义回溯状态标识,在递归操作完成后,重置状态
一种是利用swap函数(交换元素位置);相对来说,swap函数更好理解一些;
5.递归函数实现:
递归终止条件:
1.swap
子全排列的数组长度等于nums的长度时,递归终止。
2.dfs
子全排列所在层数(depth)等于nums的长度时,递归终止。
循环数组内部元素:
1.swap
通过swap,将nums[i] 与 p(从0开始)交换
调用递归函数prem,传入 nums, p+1, nums.lenght, res(结果集)
递归内部可以理解为,例如1,2,3 先将1取出,求解剩余2,3 的全排列,依次类推
当递归终止后,再次调用swap函数,将数组重置成原始状态;
2.dfs
dfs函数中传入nums,len,depth(当前所在层数),path(存储当前排列结果的动态数组),
used(元素是否已存在排列中的布尔标识), res(结果集)
调用递归dfs,判断当前元素是否在排列中used[i] === true ?,存在则跳过,不存在则
used[i] = true, 将当前nums[i] 存入path中,然后调用dfs
dfs终止后,***重点来了,回溯状态需要重置,used[i] = false,path.pop() 将当前元素从已有排列中删除
全排列属于回溯入门问题,回溯还是需要多学多练
swap解法
dfs解法
DCbryant commentedon Sep 22, 2020
const permute = nums => {
const res = [];
const len = nums.length;
const curr = [];
const use = {};
if (curr.length === len) {
res.push(curr);
}
function dfs (nth) {
for (let i = 0; i < len; i++) {
if (!use[i]) {
use[i] = 1;
curr.push(nums[i]);
dfs(i);
curr.pop();
use[i] = 0;
}
}
}
dfs(0);
return res;
};
syc666 commentedon Dec 24, 2020
感觉递归函数不需参数也可以
z253573760 commentedon Feb 2, 2021
fengmiaosen commentedon Aug 1, 2022