LeetCode 78 Subsets (Tag:Array Difficulty:Medium)

173 阅读2分钟

这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战

前言

关于 LeetCode 数组类型题目的相关解法,可见LeetCode 数组类型题目做前必看,分类别解法总结了题目,可以用来单项提高。觉得有帮助的话,记得多多点赞关注哦,感谢!

题目描述

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

示例 1:
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

示例 2:
输入:nums = [0]
输出:[[],[0]]

链接:leetcode-cn.com/problems/su…

题解

解法一:组合数
这道题目可以看作和 leetcode77类似的题目,77 题是典型的组合数题目,从 nums 数组中选择 k 个数组成新的数组,共可以组成多少个数组。而对应这道题,k 可以从 0 到 nums.length 依次增加,这样就转换为组合数题目了。代码见下方

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var subsets = function(nums) { 
    let ans = [[]]
    let curr = []
    for (let i = 1; i <= nums.length; i++) {
        Comb(nums, 0, i, 0, ans, curr)
    }
    return ans

}
var Comb = (nums, d, k, s, ans, curr) => {
    if (d === k) {
        ans.push([...curr])
        return
    }
    for (let i = s; i < nums.length; i++) {
        curr.push(nums[i])
        Comb(nums, d+1, k, i+1, ans, curr)
        curr.pop()
    }
}

时间复杂度 O(n * 2^n)

解法二:位运算
位运算本质是利用二进制的一些特性来模拟 dfs 过程。对应这道题,我们假设有一个二进制数,这个数每个位的只能取 0 或者 1,该位为 0,代表对应 nums 的元素不被选择,如果为 1,则表示该元素被选择。那么,当这个二进制数从 0 增大到所有位数都为 1 的过程中,就模拟出了 nums 的选择过程。具体怎么对应其实就是一个与运算。可以具体来看代码:

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var subsets = function(nums) { 
    let len = nums.length
    let max = 1 << len
    let ans = []
    for (let mask = 0; mask < max; mask++) {
        let curr = []
        for (let i = 0; i < len; i++) {
            if (mask & 1 << i) {  // 这里判断哪个元素对应二进制位置为 1
                curr.push(nums[i])
            }
        }
      
        ans.push(curr)
    }
    return ans
}

时间复杂度 O(n * 2^n)