数组求子集
2^n个
测试数组 let nums = [1, 6, 9, 5, 8, 10, 12, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
len = 17
长度越长,越复杂。?
方案1. 二进制的思路
1、采用二进制的思路,全0对应空集,全1对应全集
2、根据数组长度决定二进制位数
3、遍历二进制各值,使用按位与操作符,生成数组的子集
测试耗时 17.301025390625 ms
/**
* 找出数组所有的子集(2^n)
* @param {number[]} nums
* @return {number[][]}
*/
private subsets(nums: Array<number>): Array<Array<number>> {
let res = [], len = nums.length;
for (let i = 0; i < (1 << len); i++) {
let arr = [];
for (let j = 0; j < len; j++) {
if (i & (1 << j)) arr.push(nums[j]);
}
res.push(arr);
}
return res;
};
方案2.回溯算法求子集
测试耗时 11.82177734375 ms
/**
* 回溯算法:求子集问题!
* @param {number[]} nums
* @return {number[][]}
*/
private subsets1(nums: Array<number>) {
var result = [[]]; // 初始为一个二维数组
var path = [];
let used = new Array(nums.length); // false
for (let index = 0; index < nums.length; index++) {
const element = nums[index];
used[index] = false;
}
nums.sort((a, b) => { return a - b });
let backtracking = function (nums: Array<number>, startIndex: number, used: Array<boolean>) {
result.push(path.slice());
for (let i = startIndex; i < nums.length; i++) {
// used[i - 1] == true,说明同一树支candidates[i - 1]使用过
// used[i - 1] == false,说明同一树层candidates[i - 1]使用过
// 而我们要对同一树层使用过的元素进行跳过
if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
continue;
}
path.push(nums[i]);
used[i] = true;
backtracking(nums, i + 1, used);
used[i] = false;
path.pop();
}
}
backtracking(nums.slice(), 0, used);
return result;
};