46. 全排列

给定一个 没有重复数字的数组nums,返回其所有可能的全排列。 :::info 示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
] :::

思路

方法一:分治

将排列的问题分治为小问题,由小问题递归推断出最后的解。
全排列I、II - 图1

  1. var permute = function(nums) {
  2. const len = nums.length;
  3. if (len === 1) return [nums];
  4. let res = [];
  5. for (let i = 0; i < len; i++) {
  6. // 取出nums[i]
  7. let num = nums[i];
  8. // 取出num[i]的数组
  9. let rest = nums.slice(0,i).concat(nums.slice(i+1, len));
  10. // 不断递归,直到数组长度为1
  11. let restPermuteArr = permute(rest);
  12. // 合并,加入结果数组
  13. for (let item of restPermuteArr) {
  14. res.push(item.concat(num));
  15. }
  16. }
  17. return res;
  18. };

方法二:回溯法

用一个数组used记录当前元素是否被使用过,同时利用一个路径栈path存储路径。
遍历目标数组,将当前元素i存入路径栈path中并标记该元素,即used[i] = true,然后开始递归。当路径栈长度等于目标数组长度时,即说明排列元素已满,加入到结果数组res中。

  1. var permute = function(nums) {
  2. const len = nums.length;
  3. const res = [];
  4. // 定义回溯函数
  5. const backTracking = (used, path) => {
  6. if (path.length === len) res.push([...path]);
  7. for (let i = 0; i < len; i++) {
  8. // 如果当前元素被使用过,直接跳过本次循环,遍历下一个元素
  9. if (used[i]) continue;
  10. // 将当前元素加入路径栈
  11. path.push(nums[i])
  12. // 标记使用过的元素
  13. used[i] = true;
  14. backTracking(used, path);
  15. // 状态重置,撤销之前的操作
  16. path.pop();
  17. used[i] = false;
  18. }
  19. }
  20. backTracking([], []);
  21. return res;
  22. };

47. 全排列 II

给定一个可包含重复数字的序列,返回所有不重复的全排列。 :::info 输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
] ::: 本题跟 全排列 的思路一致,只不过需要在一开始排序,然后在回溯过程中增加判断去重:

  1. var permuteUnique = function (nums) {
  2. const res = [];
  3. const len = nums.length;
  4. // 先排序,目的是为了把重复的数字放到一起形成连续,便于后面判断
  5. nums.sort((a, b) => a - b);
  6. var backtracking = function (used, path) {
  7. if (path.length === len) {
  8. res.push([...path]);
  9. }
  10. for (let i = 0; i < len; i++) {
  11. if (used[i]) continue;
  12. // 现在假如 第二个数字也是 1,和第一个 1 重复了:
  13. // 1.首先下标肯定要大于等于 0
  14. // 2.前后数字相等
  15. // 3.前面的数字必须标记为 使用过了
  16. if (i - 1 >= 0 && nums[i - 1] === nums[i] && !used[i - 1]) continue;
  17. path.push(nums[i]);
  18. used[i] = true;
  19. backtracking(used, path);
  20. path.pop();
  21. used[i] = false;
  22. }
  23. }
  24. backtracking([], []);
  25. return res;
  26. };