Leetcode90. Subsets II

链接

link

思路

78.subset 的拓展
和78题不同的地方在于,这个相当于允许出现重复元素的集合。

python

1.

延续了78.的思路,最后只要去重即可。

class Solution:
    def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
        result = []
        ele_num = len(nums)
        sub_size = 2 ** ele_num
        for i in range(sub_size):
            result.append([])
        for i in range(ele_num):
            for j in range(sub_size):
                if j >> i & 1:
                    result[j].append(nums[i])
        
        return set(result)
        

unhashable type ‘list’
试过把列表转化为集合,把列表转换为元组再转换为集合,把列表转换为集合再转换为列表,都失败了。
于是上stackoverflow寻求帮助。

Sets can not contain mutable objects. Lists are mutable, meaning that you can change the contents of the list after adding it to the set.

于是有了下面这种办法

s = set(tuple(arr) for arr in result)

但是,得到的结果中,有一些是一样的,比如类似于[1,4,4]和[4,1,4]。因为他们是元组,所以顺序不同就不同,无法去重。顺序不同想要去重的话,可以用集合。因为即使顺序不同,集合只要元素相同就是一样的。但是集合去重不能用集合,因为集合是unhashable的。而且我想满足的是,去除元素相同的列表,所以转化为集合,因为只要元素相同集合即相同。但是集合内没有重复元素,这样的话,[1,4,4]就会变成[1,4]。
所以又想到了别的办法,就是让把所有列表排序,这样的话,就能去重了。

class Solution:
    def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
        result = []
        ele_num = len(nums)
        sub_size = 2 ** ele_num
        for i in range(sub_size):
            result.append([])
        for i in range(ele_num):
            for j in range(sub_size):
                if j >> i & 1:
                    result[j].append(nums[i])
        
        s = set(tuple(sorted(arr)) for arr in result)
        
        return s
        

注意这里是

sorted(arr)

不能

(arr.sort())

这个过程真的是非常地曲折,而且我觉得也不是很简洁优雅。

2.

这道题可以用回溯法,看了别人的讲解,都没看懂orz。转向万能的b站。
dfs+回溯
也就是对每个数字,取或者不取两种情况罢了。但是这里有个问题,就是子集不能重复。所以会做一点处理。首先要排个序(排序大法好)
比如数列[1, 2, 2, 2, 2, 3, 3, 3, 4, 5]。这里到了[2, 2, 2, 2]的部分,就分为[],[2],[2, 2],[2, 2, 2],[2, 2, 2, 2]的几种情况。怎么实现呢?
我没有想到好的办法,参考了别人的。

if (i > start && nums[i] === nums[i - 1]) continue;

对于连续的[2, 2, 2, 2],可能会出现重复的情况,比如[2],可以通过取第1,2,3,4个元素得到。所以规定只能通过取第一个元素取到即可。所以取了第一个之后就直接跳过后面的重复元素。
这里注意,类里面的方法,positional arguments 一定要加上self,否则会出现参数数目错误。
刚开始写的出bug了,还不知道为啥

class Solution:
    def backtrack(self, List, start, nums, temlist):
        self.List.append(temlist)
        print(self.List)  # 这里输出当前的List
        for i in range(start, len(nums)):
            if (i > start and (nums[i] == nums[i - 1])):
                continue
            temlist.append(nums[i])
            self.backtrack(List, i + 1, nums, temlist)
            temlist.pop()
            
    def subsetsWithDup(self, nums) :
        self.List = []
        temlist = []
        self.backtrack(self.List, 0, nums, temlist)
        return self.List

结果是

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

但是应该是

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

List是啥时候改变了啊?好奇怪啊
这个debug过程真的十分艰难,试图从StackOverflow上寻求帮助但是没人理我orz。
最后在函数中播撒了一堆print,发现,当temlist改变的时候,List也就随之改变了。其实刚开始隐约感觉就是这里有问题。python这个地方一直让我很迷2333
下面有一个测试的小例子。其他还有很容易搞错的地方,比如python创建二维数组

tem = []
a = []
tem.append(a)
print(tem)
a.append('b')
print(tem)

a是tem里面的列表,a改变了,tem就随之改变。
解决方法,就是把a的副本传给tem即可
在这道题中,就是每次

List.append(temlist.copy())

成功!

class Solution:
    def backtrack(self, List, start, nums, temlist):
        self.List.append(temlist.copy())
        for i in range(start, len(nums)):
            if (i > start and (nums[i] == nums[i - 1])):
                continue
            temlist.append(nums[i])
            self.backtrack(List, i + 1, nums, temlist)
            temlist.pop()
            
    def subsetsWithDup(self, nums) :
        nums.sort()
        self.List = []
        temlist = []
        self.backtrack(self.List, 0, nums, temlist)
        return self.List

经验总结

debug的时候不要怕麻烦,可以多加一些print,这样便于发现变量在不同时候的值,可以找到是哪里出了问题。
另外,如果有时间,最好能学一下调试方法。这样debug会高效很多吧。

发布了74 篇原创文章 · 获赞 4 · 访问量 1434

猜你喜欢

转载自blog.csdn.net/weixin_44814121/article/details/100830028