46. 全排列
代码
ts
function permute(nums: number[]): number[][] {
const res = [];
const len = nums.length;
const path = new Array(len).fill(0);
const onPath = new Array(len).fill(false);
function dfs(i) {
if (i === len) {
res.push([...path]);
return;
}
// 遍历所有数找到没用过的
for (let j = 0; j < len; j++) {
if (!onPath[j]) {
path[i] = nums[j];
onPath[j] = true;
dfs(i + 1);
onPath[j] = false;
}
}
}
dfs(0);
return res;
};思路
使用回溯生成所有排列:
- 定义结果数组
res,用于保存所有合法排列 - 使用数组
path记录当前已经选择的排列路径 - 使用布尔数组
onPath标记哪些数字已经被使用过 - 递归函数
dfs(i)表示当前要填排列中的第i个位置 - 每次枚举所有数字,挑选还没有使用过的数放到
path[i] - 递归进入下一层后,再撤销当前选择,继续尝试其他分支
示例
对于 nums = [1,2,3]:
- 先选
1,继续递归构造后面的排列 - 再选
2,接着选3,得到[1,2,3] - 回溯后改选
3,得到[1,3,2] - 再回到更上一层,改为从
2或3开头,继续同样过程
关键点
path用来保存当前递归路径上的排列结果onPath[j]用来避免同一个元素在同一条路径中被重复使用当
i === len时,说明已经得到一个完整排列,可以加入结果集回溯的核心是“做选择、递归、撤销选择”
时间复杂度
,其中 是排列总数,每个排列需要 的拷贝成本 空间复杂度
,主要是递归栈、 path和onPath的额外开销,不计结果数组