78.子集

78.子集

1.题目

78.子集_第1张图片

2.我的解决方案

太菜了,这道题用的思路不太会

3.官方的解决方案

回溯法:从选择和不选择的角度出发

  • 看视频:点击查看
    78.子集_第2张图片
class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        # 采用回溯法,使用深度优先遍历
        # 二叉树所有的叶子结点都是问题的解
        def dfs(nums, length, index, path, res):
            if index == length:    # 到了递归的叶子结点
                res.append(path[:])  # 将路径状态添加到结果当中(必须是path[:], 不能只是path))
                return
            dfs(nums, length, index+1, path, res)   # 不考虑该元素,进行下一层递归
            path.append(nums[index])    # 考虑该元素,就将其加入路径变量
            dfs(nums, length, index+1, path, res)
            path.pop()  # 回溯算法状态重置,在递归前做了什么操作,就在递归后做相反的操作

        length = len(nums)
        self.res = []
        path = []
        dfs(nums, length, 0, path, self.res) # 输入数组,输入数组的长度,当前考虑的元素的下标,传入路径变量(栈),结果

        return self.res
  • 时间复杂度: O ( n ∗ 2 n ) O(n*2^n) O(n2n) :形成二叉树的所有 2 n + 1 2^{n+1} 2n+1结点 O ( 2 n ) O(2^n) O(2n),保存一次结点所占用的时间为 O ( n ) O(n) O(n)
  • 空间复杂度 O ( n ) O(n) O(n) :形成二叉树的所有 2 n + 1 2^{n+1} 2n+1个结点,每个结点所占用的空间为 O ( n ) O(n) O(n)
    关于列表中插入列表遇到的问题解决方案:点击查看

按照求全排列的思路

78.子集_第3张图片

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        # 采用回溯法,使用深度优先遍历
        # 按照全排列的思路,绘制的是多叉树
        def dfs(nums, length, begin, path, res):
            res.append(path[:]) # 前序遍历
            for i in range(begin, length):  
                # i表示从num[i]为根结点,作为begin进行深度优先遍历,到了叶子结点,i++,换一个num[i]作为根节点,继续向下遍历
                path.append(nums[i])    # 考虑该元素,就将其加入路径变量
                dfs(nums, length, i+1, path, res)
                path.pop()  # 回溯算法状态重置,在递归前做了什么操作,就在递归后做相反的操作

        length = len(nums)
        self.res = []
        path = []
        dfs(nums, length, 0, path, self.res) # 输入数组,输入数组的长度,当前考虑的元素的下标,传入路径变量(栈),结果
        
        return self.res
  • 时间复杂度: O ( n ∗ 2 n ) O(n*2^n) O(n2n) :形成二叉树的所有 2 n + 1 2^{n+1} 2n+1结点 O ( 2 n ) O(2^n) O(2n),保存一次结点所占用的时间为 O ( n ) O(n) O(n)
  • 空间复杂度 O ( n ) O(n) O(n) :形成二叉树的所有 2 n + 1 2^{n+1} 2n+1个结点,每个结点所占用的空间为 O ( n ) O(n) O(n)

位运算

78.子集_第4张图片

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        # 采用位运算
        # 位运算和子集中元素的选与不选有结构上的巧合
        length = len(nums)
        size = 1 << length  # 子集的个数(左移相当于乘以2)
        res = []
        for i in range(0, size):	# 每个数字都对应了结果集中的一个子集元素
            subset = []	
            for j in range(0, length):	# 从nums开始中开始筛选放入
                # 对应的i右移j位,来从右到左判断是否选择该元素进入子集
                if((i >> j) & 1 == 1):  # 说明这个数是子集当中的元素,将其添加到子集当中
                    subset.append(nums[j])
            res.append(subset)
        return res

你可能感兴趣的:(leetcode,leetcode,python,回溯法,位运算,集合子集)