LeetCode----Subsets II

95 篇文章 0 订阅
93 篇文章 0 订阅

Subsets II

Given a collection of integers that might contain duplicates, nums, return all possible subsets.

Note:

  • Elements in a subset must be in non-descending order.
  • The solution set must not contain duplicate subsets.

For example,
If nums = [1,2,2], a solution is:

[
  [2],
  [1],
  [1,2,2],
  [2,2],
  [1,2],
  []
]

分析:

生成子集,这里的给定的子集元素有重复,要求生成的子集无重复。我在之前的博客中写过一篇生成子集的文章,这里先使用位向量法。


代码:

from itertools import compress


class Solution(object):
    def subsets(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        solutions = []
        self.dfs(0, len(nums), [], nums, solutions)
        return sorted(solutions)

    def dfs(self, cur, n, lst, nums, solutions):
        if cur == n:
            cur_ans = sorted(list(compress(nums, lst)))
            if cur_ans not in solutions:
                solutions.append(cur_ans)
        else:
            self.dfs(cur + 1, n, lst + [0], nums, solutions)
            self.dfs(cur + 1, n, lst + [1], nums, solutions)

在有重复元素的情况下,使用这种方法的代码效率并不高。

上述代码是选择决定第i个位置的元素是否选或者不选的,当给定nums为[1, 1, 2]时,选择了第一个元素和最后一个元素结果与选择了第二个元素和最后一个元素的结果想同,这样会产生重复的情况。

下面的代码能够在递归时生成的解均为非重复解。

代码:

class Solution(object):
    def subsets(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        res = []
        nums.sort()
        self.dfs(nums, len(nums), 0, [], res)
        return res

    def dfs(self, nums, n, cur, path, res):
        res.append(path)
        for i in range(cur, n):
            if i > cur and nums[i] == nums[i - 1]:  # 剔除重复的情况。
                # print i, cur, nums[i]
                continue
            self.dfs(nums, n, i + 1, path + [nums[i]], res)

上面的代码,在递归时不产生重复的解。比如当nums为[1, 1, 1, 3]时,递归会先产生[]一直到[1, 1, 1, 3],然后递归开始回退,回退到res为[1, 1]状态然后产生[1, 1, 3],然后递归继续回退,回退到res为[1](此时res中的元素1为nums中的第一个元素1)的状态然后准备添加nums中第三个元素1,而此时发现第三个元素与第二个元素值相同,则放弃添加该元素,转而添加nums中的第四个元素3,得到[1, 3],...

当递归回退后,程序不再添加相邻相同元素,这样就避免了产生相同的解,提高了效率。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值