[路飞]_46.全排列

「这是我参与2022首次更文挑战的第24天,活动详情查看:2022首次更文挑战

46. 全排列

题目

给定一个不含重复数字的数组 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]]
复制代码

题解

递归 + 回溯 + 剪枝

递归回溯所有可能结果;可以参考下图

graph TD

1 --> 1,1 & 1,2 & 1,3
1,1 --> 1,1,1 & 1,1,2 & 1,1,3
1,2 --> 1,2,1 & 1,2,2 & 1,2,3
1,3 --> 1,3,1 & 1,3,2 & 1,3,3
2 --> 2,1 & 2,2 & 2,3
2,1 --> 2,1,1 & 2,1,2 & 2,1,3
2,2 --> 2,2,1 & 2,2,2 & 2,2,3
2,3 --> 2,3,1 & 2,3,2 & 2,3,3
3 --> 3,1 & 3,2 & 3,3
3,1 --> 3,1,1 & 3,1,2 & 3,1,3
3,2 --> 3,2,1 & 3,2,2 & 3,2,3
3,3 --> 3,3,1 & 3,3,2 & 3,3,3

代码实现可以先写一份极简版,代码中有注释,看起来是不是很简单?

var permute = function(nums) {
    // 数组长度
  const len = nums.length;
  // 递归
  dfs([]);
  function dfs(path) {
      // 递归出口
    if (path.length === len)return
    for (let i = 0; i < len; i++) {
        // 统计路径上的元素并放入路径数组
        path.push(nums[i]);
        dfs(path);
        // 回溯
        path.pop();
    }
  }
  
};
复制代码

但是观察 n u m s = [ 1 , 2 , 3 ] nums = [1,2,3] 递归回溯的参考图, [ 1 , 1 , 1 ] , [ 1 , 1 , 2 ] [1,1,1],[1,1,2] 这种不符合要求的分支也构造出来了,咱们题目的要求是不含重复数字;

所以在统计路径上的元素需要有条件的统计

有条件的统计就是剪枝 符合条件的统计,不符合条件的结束递归

什么条件,不含重复数字就是条件,现在路径数组 p a t h path 记录所有已经统计到的元素,只要新元素不与 p a t h path 已经存在的元素相等即可

根据这个思路写一个 i s C h e c k isCheck 函数;看注释,很简单的

function isCheck(path, i) {
    // path 该递归路径上已经选择的元素,
    // i 想将i这个元素放入 path 不知道行不行
    for (let j = 0; j < path.length; j++) {
        // 不行啊,递归路径上已经选择过这个元素了
      if (path[j] === i) return false;
    }
    // 可以,放吧
    return true;
  }
复制代码

根据上述思路编辑代码如下

时间复杂度: O ( n n ! ) O(n * n!)

完整代码代码

var permute = function(nums) {
  const len = nums.length;
  const result = [];
  dfs([]);
  return result;
  function dfs(path) {
    if (path.length === len) {
      result.push([...path]);
      return;
    }

    for (let i = 0; i < len; i++) {
      if (isCheck(path, nums[i])) {
        path.push(nums[i]);
        dfs(path);
        path.pop();
      }
    }
  }

  function isCheck(path, i) {
    for (let j = 0; j < path.length; j++) {
      if (path[j] === i) return false;
    }
    return true;
  }
};
复制代码

结语

递归 + 回溯 + 剪枝 是比较经典的算法。作者刚开始学习,不足之处敬请谅解,如有意见建议欢迎评论区讨论

Guess you like

Origin juejin.im/post/7063010320444784648