共计 1302 个字符,预计需要花费 4 分钟才能阅读完成。
原题
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:
输入: nums = [1,2,3]
输出:
[[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]]
思路
使用位移和按位与的思路,来自 leetcode 的评论区。这个思路相对来说比较抽象,下面是具体的解释。
举一个例子????,nums = [a, b, c]
, 如果数组中所有的子项全都存在,我们可以将其抽象成一个二进制数,111
(1 代表数字存在)
子集 | 二进制数 |
---|---|
[] | 000 |
[a] | 100 |
[b,c] | 110 |
[a,c] | 101 |
[a,b,c] | 111 |
[b] | 010 |
[b,c] | 011 |
001 |
111
的十进制数表示是 7, 000
的十进制数表示是 0,我们只需要遍历从 0 到 7 的十进制数即可得到所有的子集。
如何将二进制数,反序列化为集合呢?我们可以利用按位与 & 操作符。
举一个例子????。例如:110
表示 [a,b]
, 我们使用,110 & 100
等于 1,表示 a
存在。110 & 010
等于 1,表示 b
存在。110 & 001
等于 0,表示 c
不存在。
子集 | A | B | C |
---|---|---|---|
[] | 000 & 100 === 0 | 000 & 010 === 0 | 000 & 001 === 0 |
[a] | 100 & 100 === 1 | 100 & 010 === 0 | 100 & 001 === 0 |
[b,c] | 110 & 100 === 1 | 110 & 010 === 1 | 110 & 001 === 0 |
…… | …… | …… |
代码
解答 1
假设参数数组的长度为 4。我们该怎么获取子集的数量呢?我们由上面???? 的思路可知,如果数组长度为 4,那么集合的数量就为0b1111
。
/**
* @param {number[]} nums
* @return {number[][]}
*/
var subsets = function(nums) {
// 子集的数量
let len = ''
const result = [[]]
for (let i = 0; i < nums.length; i++) {len += '1'}
// 获取最大的子集数量,[1, 2, 3]最大子集数量 `0b111 === 7`
len = parseInt(len, 2)
for (let i = 1; i <= len; i++) {let temp = []
// 1 << 0 `0b001`
// 1 << 1 `0b010`
// 1 << 2 `0b100`
// 判断每一个位置是否存在
for (let j = 0; j < nums.length; j++) {if (i & (1 << j)) {temp.push(nums[j])
}
}
result.push(temp)
}
return result
};
解答 2
/**
* @param {number[]} nums
* @return {number[][]}
*/
var subsets = function(nums) {let result = []
for (let i = 0; i < nums.length; i++) {let temp = []
for (let j = 0; j < result.length; j++) {temp.push([...result[j], nums[i]])
}
result = [...result, ...temp, [nums[i]]]
}
result = [...result, []]
return result
};
正文完
发表至: javascript
2019-08-26