排列组合子集
作者:互联网
子集(元素无重不可复选)
[a,b,c] 的全部子集为 [] [a] [b] [c] [a,b] [a,c] [b,c] [a,b,c]
let res = []; // 记录回溯算法的递归路径 let track = []; // 回溯算法核心函数,遍历子集问题的回溯树 function backtrack( nums, start) { // 前序位置,每个节点的值都是一个子集 res.push([...track]); // 回溯算法标准框架 for (let i = start; i < nums.length; i++) { // 做选择 track.push(nums[i]); // 通过 start 参数控制树枝的遍历,避免产生重复的子集 backtrack(nums, i + 1); // 撤销选择 track.pop(); } } backtrack(['a', 'b', 'c'], 0); console.log(res);
组合(元素无重不可复选)
[a,b,c] 的2元素的所有组合为 [a,b] [a,c] [bc]
let res = []; // 所有组合的结果 let track = []; // 记录回溯算法的递归路径 let max = 2; // 组合的个数 // 回溯算法核心函数,遍历子集问题的回溯树 function backtrack( nums, start) { // 前序位置,每个节点的值都是一个子集 if(max === track.length){ res.push([...track]); return; } // 回溯算法标准框架 for (let i = start; i < nums.length; i++) { // 做选择 track.push(nums[i]); // 通过 start 参数控制树枝的遍历,避免产生重复的子集 backtrack(nums, i + 1); // 撤销选择 track.pop(); } } backtrack(['a', 'b', 'c'], 0); console.log(res);
排列(元素无重不可复选)
标准全排列可以抽象成如下这棵二完全叉树:
[a,b,c] 的2元素的所有排列为 [a,b] [a,c] [b,a] [b,c] [c,a] [c,b]
let res = []; // 所有排列的结果 let track = []; // 记录回溯算法的递归路径 let max = 2; // 排列的个数 let used = []; // 记录已经使用了的序号,防止重复 // 回溯算法核心函数,遍历子集问题的回溯树 function backtrack(nums) { // 前序位置,每个节点的值都是一个子集 if (max === track.length) { res.push([...track]); return; } // 回溯算法标准框架 for (let i = 0; i < nums.length; i++) { if (used[i]) { // 已经存在 track 中的元素,不能重复选择 continue; } // 做选择 track.push(nums[i]); used[i] = true; // 通过 start 参数控制树枝的遍历,避免产生重复的子集 backtrack(nums); // 撤销选择 track.pop(); used[i] = false; } } backtrack(['a', 'b', 'c']); console.log(res);
子集/组合(元素可重不可复选)
[a,b,b] 的全部子集为 [] [a] [b] [a,b] [b,b] [a,b,b]
[a,b,b]需要先进行排序,让相同的元素靠在一起,如果发现 nums[i] == nums[i-1]
,则跳过
let res = []; // 所有组合的结果 let track = []; // 记录回溯算法的递归路径 // 回溯算法核心函数,遍历子集问题的回溯树 function backtrack( nums, start) { // 前序位置,每个节点的值都是一个子集 res.push([...track]); // 回溯算法标准框架 for (let i = start; i < nums.length; i++) { // 剪枝逻辑,值相同的相邻树枝,只遍历第一条 if (i > start && nums[i] == nums[i - 1]) { continue; } // 做选择 track.push(nums[i]); // 通过 start 参数控制树枝的遍历,避免产生重复的子集 backtrack(nums, i + 1); // 撤销选择 track.pop(); } } let arr = ['a', 'b', 'b']; arr.sort(); // 排序,将相同元素放在一起 backtrack(arr, 0); console.log(res);
排列(元素可重不可复选)
[a,b,b] 的3元素的所有排列为 [a,b,b] [b,a,b] [b,b,a]
nums[i] === prevNum 这一句,就是去重,因为如果两个节点是一样的,则其对应的树也是一样的,所以会产生重复。 如 [a,b,b]的排列 [a,b,b'] [a,b',b]let res = []; // 所有排列的结果 let track = []; // 记录回溯算法的递归路径 let max = 3; // 排列的个数 let used = []; // 记录已经使用了的序号,防止重复 // 回溯算法核心函数,遍历子集问题的回溯树 function backtrack(nums) { // 前序位置,每个节点的值都是一个子集 if (max === track.length) { res.push([...track]); return; } // 回溯算法标准框架 let prevNum = -666666; // 一个不可能出现在nums中的值 for (let i = 0; i < nums.length; i++) { if (used[i]) { // 已经存在 track 中的元素,不能重复选择 continue; } // 新添加的剪枝逻辑,固定相同的元素在排列中的相对位置 if ( nums[i] === prevNum) { continue; } // 做选择 track.push(nums[i]); used[i] = true; prevNum = nums[i]; // 通过 start 参数控制树枝的遍历,避免产生重复的子集 backtrack(nums); // 撤销选择 track.pop(); used[i] = false; } } let arr = ['a', 'b', 'b']; arr.sort(); // 排序,将相同元素放在一起 backtrack(arr); console.log(res);
子集/组合(元素无重可复选)
[a,b]的所有小于等于3的可复选子集为: [] [a] [a, a] [a,b] [a,c] [b] [b,b] [b,c] [c] [c,c]
let res = []; // 记录回溯算法的递归路径 let track = []; let max = 2; // 最大数量 // 回溯算法核心函数,遍历子集问题的回溯树 function backtrack( nums, start) { // 前序位置,每个节点的值都是一个子集 res.push([...track]); if(track.length >= 2){ return; } // 回溯算法标准框架 for (let i = start; i < nums.length; i++) { // 做选择 track.push(nums[i]); // 通过 start 参数控制树枝的遍历,避免产生重复的子集 backtrack(nums, i); // 注意,这里的i不加1,表示下一层使用的序号>=i,但是同一层上从左到右还是递增 // 撤销选择 track.pop(); } } backtrack(['a', 'b', 'c'], 0); console.log(res);
标签:nums,track,回溯,let,子集,排列组合,backtrack 来源: https://www.cnblogs.com/xiafl/p/16298559.html