Leetcode 78:子集(最详细的解法!!!)

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

**说明:**解集不能包含重复的子集。

示例:

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

解题思路

这个问题通过递归可以很快的解决,我们只要知道了subsets(nums[1:]),那么我们只要将nums[0]添加到每个子集的前面形成新的子集,然后将新的子集添加到result中即可。

class Solution:
    def subsets(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        if not nums:
            return [[]]
        result = self.subsets(nums[1:])
        return result + [[nums[0]] + s for s in result]

这个问题我们也可以通过回溯法来解决。

class Solution:
    def subsets(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        result = list()
        self._subsets(nums, 0, list(), result)
        return result
    
    def _subsets(self, nums, index, path, result):
        result.append(path)
        for i in range(index, len(nums)):
            self._subsets(nums, i + 1, path + [nums[i]], result)

很多人很难理解为什么上面这种写法是回溯法,其实我们将pushpop的过程合到了一块,我在之前的一些问题中也没说明,所以我在此解释一下。

self._subsets(nums, i + 1, path + [nums[i]], result)

可以将它分开写成

path.append(nums[i])
self._subsets(nums, i + 1, path, result)
path.pop()

同样的,对于递归可以解决的问题,我们都应该思考是不是可以通过迭代解决。

class Solution:
    def subsets(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        result = [[]]
        for num in nums:
            result += [item+[num] for item in result]
        return result

非常的简洁。最后介绍一种hacker的编码

class Solution:
    def subsets(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        return [[nums[j] for j in range(len(nums)) if i>>j&1] for i in range(2**len(nums))]

我们通过for i in range(2**len(nums))建立一组mask,以题目中的例子为例

00000000
00000001
00000010
00000011
00000100
00000101
00000110
00000111

然后我们通过对mask中的每个编码移位,并且和1进行&操作,如果为true,那么将nums[j]添加到result中。

我将该问题的其他语言版本添加到了我的GitHub Leetcode

如有问题,希望大家指出!!!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值