题目:
给定一个不含重复数字的数组 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]]
提示:
1 <= nums.length <= 6
-10 <= nums[i] <= 10
nums 中的所有整数 互不相同
核心思路: 【回溯算法】
就是递归到底,把所有符合条件的都找出来,期间会涉及到剪枝,比如 “1,1,xxxxx”这种直接跳过,不成立的。
下面以[1,2,3]这个数组为例,来看具体的回溯思路。
每一位都有3种选择:1、2、3。
每一次都做选择,展开出一棵空间树。
利用约束条件「不能重复选」,做剪枝,剪去不会产生正确解的选项(分支)。
利用 hashMap,记录选过的数,下次遇到相同的数,跳过。
dfs 函数:基于当前的 path,继续选数,直到构建出合法的 path,加入解集。
维护状态:公用一个path,并且维护一个used标识path中当前元素的状态。
递归的入口:dfs 执行传入空 path,什么都还没选。
函数体内,用 for loop 枚举出当前所有的选项,并用 if 语句跳过剪枝项。
每一轮迭代,作出一个选择,基于它,继续选(递归调用)。 递归的出口:当构建的 path 数组长度等于 nums 长度,就选够了,加入解集。
解:
const permute = (nums) => {
const res = [];
const used = {}; //公用,伴随stack做状态标识
function dfs(path) {
if (path.length == nums.length) { // 个数选够了
res.push(path.slice()); // 拷贝一份path,加入解集res
return; // 结束当前递归分支
}
for (const num of nums) { // for枚举出每个可选的选项
// if (path.includes(num)) continue; // 别这么写!查找是O(n),增加时间复杂度
if (used[num]) continue; // 使用过的,跳过
path.push(num); // 选择当前的数,加入path
used[num] = true; // 记录一下 使用了
dfs(path); // 基于选了当前的数,递归
path.pop(); // 上一句的递归结束,回溯,将最后选的数pop出来
used[num] = false; // 撤销这个记录
}
}
dfs([]); // 递归的入口,空path传进去
return res;
};
———— 前端、Javascript实现、算法、刷题、leetcode