leetcode78子集

20次阅读

共计 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
};

正文完
 0