「这是我参与2022首次更文挑战的第24天,活动详情查看:2022首次更文挑战」
题目
给定一个不含重复数字的数组 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();
}
}
};
复制代码
但是观察 递归回溯的参考图, 这种不符合要求的分支也构造出来了,咱们题目的要求是不含重复数字;
所以在统计路径上的元素需要有条件的统计
有条件的统计就是剪枝
符合条件的统计,不符合条件的结束递归
什么条件,不含重复数字就是条件,现在路径数组 记录所有已经统计到的元素,只要新元素不与 已经存在的元素相等即可
根据这个思路写一个 函数;看注释,很简单的
function isCheck(path, i) {
// path 该递归路径上已经选择的元素,
// i 想将i这个元素放入 path 不知道行不行
for (let j = 0; j < path.length; j++) {
// 不行啊,递归路径上已经选择过这个元素了
if (path[j] === i) return false;
}
// 可以,放吧
return true;
}
复制代码
根据上述思路编辑代码如下
时间复杂度:
完整代码代码
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;
}
};
复制代码
结语
递归 + 回溯 + 剪枝 是比较经典的算法。作者刚开始学习,不足之处敬请谅解,如有意见建议欢迎评论区讨论