给定一个不含重复数字的数组 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]]
var permute = function(nums) {
const result = [];
if (nums.length === 1) {
return [nums];
} else { //遍历每一项
for (let i = 0; i < nums.length; i++) {
let first = nums[i]; //拿到当前的元素
let left = nums.slice(0, i).concat(nums.slice(i + 1)); //除当前元素的其他元素组合
let rest = permute(left); //上一次递归返回的全排列
for (let j = 0; j < rest.length; j++) { //组合在一起
let next = [first].concat(rest[j]);
result.push(next);
}
}
}
return result;
};
这道题主要是利用了算法的回溯思想,算法的截止条件是当数组里面只剩一个数的时候返回它本身,将每次遍历时的 i 取出,剩下的组成新的数组,新的数组不断地回溯,最终实现全排列
代码分析
逐步分析 permute
函数如何对数组 [1, 2, 3]
进行全排列。
-
初始调用:
nums = [1, 2, 3]
- 调用
permute(nums)
。
-
基本情况检查:
nums.length
是3,不等于1,所以不满足基本情况,继续执行循环。
-
循环遍历数组:
- 第一次循环,
i = 0
:first = nums[0]
即first = 1
left = nums.slice(1)
即left = [2, 3]
- 递归调用
permute(left)
:nums = [2, 3]
,继续同样的逻辑。
- 第一次循环,
-
递归调用:
- 对
[2, 3]
进行同样的步骤:- 第一次循环(
i = 0
),first = 2
,left = [3]
,递归调用permute([3])
。 permute([3])
满足基本情况,返回[[3]]
。- 将
[3]
与first = 2
结合,得到[2, 3]
并添加到结果中。
- 第一次循环(
- 对
-
继续递归:
- 回到
[2, 3]
的permute
调用,进行第二次循环(i = 1
):first = 3
,left = [2]
,递归调用permute([2])
。permute([2])
同样满足基本情况,返回[[2]]
。- 将
[2]
与first = 3
结合,得到[3, 2]
并添加到结果中。
- 回到
-
组合结果:
- 现在我们已经得到了
[2, 3]
和[3, 2]
的排列,将它们与最初的first = 1
结合:- 结合
[1]
和[2, 3]
得到[1, 2, 3]
。 - 结合
[1]
和[3, 2]
得到[1, 3, 2]
。
- 结合
- 现在我们已经得到了
-
完成第一次循环:
- 继续
nums
的外层循环,i = 1
:first = 2
,left = [1, 3]
,递归调用permute([1, 3])
。
- 对
[1, 3]
重复上述步骤,得到排列[2, 1, 3]
和[3, 1, 2]
。
- 继续
-
完成第二次循环:
- 最后,
i = 2
:first = 3
,left = [1, 2]
,递归调用permute([1, 2])
。
- 再次重复,得到排列
[3, 1, 2]
和[3, 2, 1]
。
- 最后,
-
最终结果:
- 所有这些排列被添加到
result
数组中,最终返回包含所有全排列的数组。
- 所有这些排列被添加到