90子集

题目:给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。说明:解集不能包含重复的子集。

输入:[1,2,2]   输出:[[2],[1],[1,2,2],[2,2],[1,2],[]]

来源:https://leetcode-cn.com/problems/subsets-ii/

法一:自己的代码   时间超过百分之98

思路:通过画图观察出剪枝条件,如果上一个是一个节点与上一个数值相等,且上一个是入栈,下一个是出栈,则需要剪掉,排序后先对相同的数字进行判断可以节省更多的时间.

from typing import List
from collections import Counter
class Solution:
    def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
        results = []
        l = len(nums)
        # 法一
        # 将数字按出现频率由高到低排序,目的是提前剪枝来减少剪枝的次数,
        # nums = [item for items, c in Counter(nums).most_common() for item in [items] * c]
        # 这样时间会更短些,如果没有重复元素直接排序,如果有在按频率排序
        # 法二
        if l == len(set(nums)):
            nums.sort()
        else:
            nums = [item for items, c in Counter(nums).most_common() for item in [items] * c]  
        def backtrack(a=[], nums=nums,count=0,sign=0):
            if count == l:
                results.append(a[:])
                print(results)
                return
            for i in [nums[count]]:
                count += 1
                # 通过画图可以观察出,当两个数相同时,如果上一个节点是入栈,下一个节点是出栈,则该枝必须剪掉,
                # 这个剪枝条件等价于如果上一个节点是出栈,下一个是入栈,二者是充要条件,
                # sign用于标记是出栈还是入栈

                # if条件用于判别是否执行剪枝
                if (count>1) & (nums[count-1] == nums[count-2]) & (sign==0):
                    a.append(i)
                    sign = 0
                    backtrack(a,count=count,sign=sign)
                    # 以后关于栈的问题,压栈后务必要记得出栈,否则很容易出错
                    a.pop()
                    # 后面的不执行的即剪掉的枝
                else:
                    a.append(i)
                    sign = 0
                    backtrack(a,count=count,sign=sign)
                    a.pop()
                    sign = 1
                    backtrack(a,count=count,sign=sign)
        backtrack()
        return results
if __name__ == '__main__':
    duixiang = Solution()
    a = duixiang.subsetsWithDup([1, 2,1, 2])
    print(a)
View Code

猜你喜欢

转载自www.cnblogs.com/xxswkl/p/11965952.html