全排列问题
从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。
示例:
输入: [1,2,3]
输出: [
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]]
题解:
/**
* @param {number[]} nums
* @return {number[][]}
*/
const permute = function(nums){
const res = [];
const cur = [];
const visited = {};
const dfs = (nth) => {
if(nth === nums.length){
res.push(cur.slice());
return;
}
for(let i = 0; i < nums.length; i++){
if(!visited[nums[i]]){
visited[nums[i]] = true;
cur.push(nums[i]);
//递归
dfs(nth + 1);
//回溯
cur.pop();
//去除已使用标志
visited[nums[i]] = false;
}
}
}
//从索引0开始
dfs(0);
return res;
}
规则:
“重复”的内容,就是递归式;“重复”的终点,就是递归边界。
组合问题
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
示例:
说明:解集不能包含重复的子集。
输入: nums = [1,2,3]
输出:
[[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]]
题解:
/**
* @param {number[]} nums
* @return {number[][]}
*/
const subsets = function(nums){
const res = [];
const subset = [];
const dfs = (index) => {
res.push(subset.slice());
for(let i = index; i < nums.length; i++){
subset.push(nums[i]);
// 基于当前数字存在于组合中的情况,进一步 dfs
dfs(i + 1);
//回溯,不参与填坑则出坑
subset.pop();
}
}
dfs(0);
return res;
}
规则:
穷举出现了,大概率会用到 DFS。
限定组合问题
给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。
示例:
输入: n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
题解:
/**
* @param {number} n
* @param {number} k
* @return {number[][]}
*/
const combine = function(n, k){
const res = [];
const subset = [];
const dfs = (index) => {
//处理边界
if(subset.length === k){
res.push(subset.slice());
return;
}
for(let i = index; i <= n; i++){
subset.push(i);
//基于当前数进行递归
dfs(i + 1);
//回溯,移除当前不符组合元素
subset.pop();
}
}
return res;
}
规则:
DFS 算法其实就是回溯思想的体现。