力扣78题:生成子集

简介: 力扣78题:生成子集

作者介绍:10年大厂数据\经营分析经验,现任大厂数据部门负责人。

会一些的技术:数据分析、算法、SQL、大数据相关、python

欢迎加入社区:码上找工作

作者专栏每日更新:

LeetCode解锁1000题: 打怪升级之旅

python数据分析可视化:企业实战案例

python源码解读

备注说明:方便大家阅读,统一使用python,带必要注释,公众号 数据分析螺丝钉 一起打怪升级

本文详细介绍了五种生成数组子集的方法,包括回溯法、迭代法和位掩码法,提供了代码示例和性能分析,旨在帮助开发者选择最适合的实现方式

题目描述

本题来自Leetcode 78

给你一个整数数组 nums,数组中的元素 互不相同。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

输入格式
  • nums:一个整数数组。
输出格式
  • 返回一个列表,其中包含所有可能的子集。

示例

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

方法一:回溯法

解题步骤
  1. 定义递归函数:使用递归函数 backtrack 来生成所有可能的子集。
  2. 递归选择:从当前位置开始,递归地选择下一个元素加入子集或不加入,直到遍历完数组。
完整的规范代码
def subsets(nums):
    """
    使用回溯法生成所有可能的子集
    :param nums: List[int], 输入的整数数组
    :return: List[List[int]], 所有可能的子集
    """
    res = []
    subset = []
    def backtrack(start):
        res.append(subset.copy())
        for i in range(start, len(nums)):
            subset.append(nums[i])
            backtrack(i + 1)
            subset.pop()
    backtrack(0)
    return res
# 示例调用
print(subsets([1, 2, 3]))  # 输出: [[],[1],[2],[3],[1,2],[1,3],[2,3],[1,2,3]]
算法分析
  • 时间复杂度:(O(N * 2^N)),其中 (N) 是数组的长度。生成所有子集并复制到输出列表中每个子集需要 (O(N)) 时间。
  • 空间复杂度:(O(N)),递归过程中的栈深度最大为 (N)。

方法二:迭代法

解题步骤
  1. 迭代添加:开始时子集只包含空集,遍历每个数字,将其添加到现有的所有子集中,形成新的子集。
完整的规范代码
def subsets(nums):
    """
    使用迭代法生成所有可能的子集
    :param nums: List[int], 输入的整数数组
    :return: List[List[int]], 所有可能的子集
    """
    res = [[]]
    for num in nums:
        res += [item + [num] for item in res]
    return res
# 示例调用
print(subsets([1, 2, 3]))  # 输出: [[],[1],[2],[3],[1,2],[1,3],[2,3],[1,2,3]]
算法分析
  • 时间复杂度:(O(N * 2^N)),其中 (N) 是数组的长度。每个步骤中,子集的数量加倍。
  • 空间复杂度:(O(N * 2^N)),存储所有子集。

方法三:位掩码

解题步骤
  1. 位掩码表示:每个子集可以由一个长度为 (N) 的位掩码表示,其中 (N) 是数组的长度。位掩码中的每一位表示对应位置的元素是否存在于子集中。
完整的规范代码
def subsets(nums):
    """
    使用位掩码生成所有可能的子集
    :param nums: List[int], 输入的整数数组
    :return: List[List[int]], 所有可能的子集
    """
    n = len(nums)
    res = []
    for i in range(2 ** n, 2 ** (n + 1)):
        # 生成位掩码,从 2^n 到 2^(n+1) - 1
        bitmask = bin(i)[3:]
        res.append([nums[j] for j in range(n) if bitmask[j] == '1'])
    return res
# 示例调用
print(subsets([1, 2, 3]))  # 输出: [[1, 2, 3], [1, 2], [1, 3], [1], [2, 3], [2], [3], []]
算法分析
  • 时间复杂度:(O(N * 2^N)),需要 (2^N) 次迭代,每次迭代中构造子集的时间复杂度为 (O(N))。
  • 空间复杂度:(O(N * 2^N)),存储所有子集。

方法四:二进制数序列

解题步骤
  1. 二进制增加:每一个子集可以通过对应的二进制数来表示,通过递增二进制数生成所有可能的子集。
完整的规范代码
def subsets(nums):
    """
    使用二进制数序列生成所有可能的子集
    :param nums: List[int], 输入的整数数组
    :return: List[List[int]], 所有可能的子集
    """
    res = []
    n = len(nums)
    for i in range(2 ** n):
        subset = [nums[j] for j in range(n) if (i & (1 << j))]
        res.append(subset)
    returnres
# 示例调用
print(subsets([1, 2, 3]))  # 输出: [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
算法分析
  • 时间复杂度:(O(N * 2^N)),其中 (N) 是数组的长度。需要 (2^N) 次迭代,每次迭代中构造子集的时间复杂度为 (O(N))。
  • 空间复杂度:(O(N * 2^N)),存储所有子集。

方法五:库函数

解题步骤
  1. 使用库函数:利用 Python 的 itertools 模块中的 combinations 函数来生成所有可能的子集。
完整的规范代码
from itertools import combinations
def subsets(nums):
    """
    使用库函数生成所有可能的子集
    :param nums: List[int], 输入的整数数组
    :return: List[List[int]], 所有可能的子集
    """
    res = []
    for i in range(len(nums) + 1):
        for combo in combinations(nums, i):
            res.append(list(combo))
    return res
# 示例调用
print(subsets([1, 2, 3]))  # 输出: [[], [1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
算法分析
  • 时间复杂度:(O(N * 2^N)),尽管内置函数高效,但基本上还是需要遍历所有可能的组合。
  • 空间复杂度:(O(N * 2^N)),需要存储 (2^N) 个子集,每个子集最多含有 (N) 个元素。

不同算法的优劣势对比

特征 方法一:回溯法 方法二:迭代法 方法三:位掩码 方法四:二进制数序列 方法五:库函数
时间复杂度 (O(N * 2^N)) (O(N * 2^N)) (O(N * 2^N)) (O(N * 2^N)) (O(N * 2^N))
空间复杂度 (O(N)) (O(N * 2^N)) (O(N * 2^N)) (O(N * 2^N)) (O(N * 2^N))
优势 易于理解,灵活 直接且简单 利用位操作效率高 直观且容易实现 利用成熟的库,代码简洁
劣势 递归可能复杂 子集构建重复 需理解位操作 直接处理二进制较抽象 性能依赖库实现,灵活性差

应用示例

数据科学:在特征选择中,可以用来生成特征的所有可能组合,帮助分析哪些特征组合对模型效果最好。

机器学习:在进行模型训练之前,可能需要对不同的特征组合进行测试,以确定最有效的特征集。

教学与研究:在算法课程中,可以使用这些方法来教学组合生成的不同技术和优化方法。

这些方法提供了多种生成子集的途径,适用于不同的场景和需求,选择合适的方法可以提高代码效率和可读性。

欢迎关注微信公众号 数据分析螺丝钉

相关文章
|
7月前
|
Go
golang力扣leetcode 416.分割等和子集
golang力扣leetcode 416.分割等和子集
49 0
|
7月前
leetcode-1994:好子集的数目
leetcode-1994:好子集的数目
68 0
|
4月前
|
算法
LeetCode第90题子集II
LeetCode第90题"子集II"的解题方法,通过排序和回溯算法生成所有不重复的子集,并使用一个boolean数组来避免同一层中的重复元素,展示了解决这类问题的编码技巧。
LeetCode第90题子集II
|
4月前
|
Python
【Leetcode刷题Python】416. 分割等和子集
LeetCode 416题 "分割等和子集" 的Python解决方案,使用动态规划算法判断是否可以将数组分割成两个元素和相等的子集。
41 1
|
4月前
|
索引 Python
【Leetcode刷题Python】78. 子集
LeetCode题目78的Python编程解决方案,题目要求给定一个互不相同的整数数组,返回该数组所有可能的子集(幂集),且解集中不能包含重复的子集。
29 1
|
4月前
|
算法
LeetCode第78题子集
文章分享了LeetCode第78题"子集"的解法,使用递归和回溯算法遍历所有可能的子集,展示了将子集问题视为树形结构进行遍历的解题技巧。
|
6月前
|
机器学习/深度学习 存储 算法
LeetCode题目 90:五种算法 回溯\迭代\位掩码\字典树\动态规划实现 子集ll
LeetCode题目 90:五种算法 回溯\迭代\位掩码\字典树\动态规划实现 子集ll
|
7月前
|
算法
leetcode代码记录(子集
leetcode代码记录(子集
32 0
|
7月前
|
Go
golang力扣leetcode 90.子集II
golang力扣leetcode 90.子集II
37 1
|
7月前
|
Java
leetcode-90:子集 II
leetcode-90:子集 II
44 1