Leetcode46 图解全排列 | 刷题打卡

209 阅读2分钟

题目描述

给定一个 没有重复 数字的序列,返回其所有可能的全排列。

示例

示例1:

输入: [1,2,3]
输出:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

题目分析

题目要求很简单,就是给定一个数组,然后返回数组中所有能够排列出的且不重复的数组。

解题思路

那么这题就不同于之前的题目了,这题得用回溯算法。

那么什么是回溯算法呢?回溯算法其实就是穷举法,不过回溯算法中用了剪枝函数,剪去了一些不可能达到最终状态(即答案状态)的节点,从而减少状态空间树节点的生成。

这么说的话,可能还不是那么的具体,那就看这张图吧。

image.png

就本题而言,因为需要返回不重复的数组,那么回溯中就要一些剪枝的操作,只有碰到跟自己不同的才会继续向下执行,碰到相同的就跳过;每一个分支递归结束后,都需要去另一个分支进行递归,所以,我们需要撤销当前的选择,回到之前的选择状态,进入下一个分支重复之前的操作。

就有点类似于树的深度优先遍历,就一条道走到底,发现走不通了就回到上一级分支,如果上一级分支还有未走过的,就从未走过的分支开始;就这样循环往复,直到每一条分支都走完。

AC代码

var permute = function(nums) {
  let res = []
  let recursion = (path, set) => {
      if(path.length == nums.length) { // 当 path 中长度跟给定数组的长度相同时
      // 说明已经有一条path满足条件了,结束当前递归
          res.push(path.concat()) // 将满足条件的 path 放进集合数组中
          return // 递归出口
      }
      for(let i = 0 ; i < nums.length; i++) { // 遍历
          if(!set.has(nums[i])) { // 如果set中不存在该元素
              path.push(nums[i]) // 就将它push进path中
              set.add(nums[i]) // 同时将该元素存进 set 中

              recursion(path,set) // 每一次递归结束之后,都需要将当前的选择清除
              path.pop() // 所以path就需要一步步的将当前选择删除
              set.delete(nums[i]) // set跟path一样
          }
      }
  }
  recursion([],new Set()) // 递归入口
  return res
};

总结

对于回溯算法还是需要多多练习呀,我相信多做些用回溯的算法题会对回溯了解更深一些。如果文中有什么讲的不好的或者需要修改的地方,欢迎到评论区留言,好让我及时发现问题,谢谢各位xdm了。

本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情