LeetCode 78:子集生成全攻略

题目LeetCode78

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

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

示例 1:

输入: nums = 1,2,3
输出:\[,1,2,1,2,3,1,3,2,3,1,2,3]

Python解法

解法一(追加)

python 复制代码
class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        res = [[]]
        for num in nums:
            for i in range(len(res)):
                res.append(res[i] + [num])
        return res

解释

在空集的基础上,循环追加后面的数据

python 复制代码
for num in nums:
    # 把当前结果里的每个子集都拿出来,加上 num,再放回 res
    for i in range(len(res)):
        res.append(res[i] + [num])

过程演示

以示例为例

① 处理第一个数:1

把 res 里的每个子集 + 1,再追加进去:

  • \] + \[1\] = \[1

res 变成:[ [], [1] ]


② 处理第二个数:2

把当前 res 里的每个子集 + 2

  • \] + \[2\] = \[2

  • 1\] + \[2\] = \[1,2

res 变成:[ [], [1], [2], [1,2] ]


③ 处理第三个数:3

把当前 res 里的每个子集 + 3

  • \] + \[3\] = \[3

  • 1\] + \[3\] = \[1,3

  • 2\] + \[3\] = \[2,3

  • 1,2\] + \[3\] = \[1,2,3

res 最终:[ [], [1], [2], [1,2], [3], [1,3], [2,3], [1,2,3] ]

解法二(搜索)

python 复制代码
class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        res = []
        self.dfs(nums, 0, [], res)
        return res
    def dfs(self, nums, index, path, res):
        res.append(path.copy())
        for i in range(index, len(nums)):
            path.append(nums[i])
            self.dfs(nums, i + 1, path, res)
            path.pop()

解释

index:当前走到第几个数

path:当前正在选的子集

res:最终结果

主要是搜索函数

python 复制代码
    def dfs(self, nums, index, path, res):
        # 每一步都把当前路径加入答案
        res.append(path.copy())
        
        # 从 index 开始往后选
        for i in range(index, len(nums)):
            path.append(nums[i])       # 选 nums[i]
            self.dfs(nums, i + 1, path, res) # 递归往后
            path.pop()                 # 不选 nums[i],回溯

过程演示

  • 一开始:path = [] → 存 []
  • 选 1 → path = [1] → 存 [1]
    • 再选 2 → path = [1,2] → 存 [1,2]
      • 再选 3 → path = [1,2,3] → 存 [1,2,3]
      • 不选 3 → 退回
    • 不选 2,选 3 → path = [1,3] → 存 [1,3]
  • 不选 1,选 2 → path = [2] → 存 [2]
    • 再选 3 → path = [2,3] → 存 [2,3]
  • 不选 1、2,选 3 → path = [3] → 存 [3]

最后:\[, 1, 1,2, 1,2,3, 1,3, 2, 2,3, 3]

Java解法

解法一(追加)

java 复制代码
import java.util.List;
import java.util.ArrayList;

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        // 初始加入空集合
        res.add(new ArrayList<>());

        // 标准普通for遍历每个数字
        for (int k = 0; k < nums.length; k++) {
            int num = nums[k];
            int size = res.size();
            // 遍历当前已存在的所有子集
            for (int i = 0; i < size; i++) {
                // 复制原有子集
                List<Integer> temp = new ArrayList<>(res.get(i));
                temp.add(num);
                res.add(temp);
            }
        }
        return res;
    }
}

解法二(搜索)

java 复制代码
class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        backtrack(nums, 0, new ArrayList<>(), res);
        return res;
    }

    private void backtrack(int[] nums, int index, List<Integer> path, List<List<Integer>> res) {
        res.add(new ArrayList<>(path));
        for (int i = index; i < nums.length; i++) {
            path.add(nums[i]);
            backtrack(nums, i + 1, path, res);
            path.remove(path.size() - 1);
        }
    }
}

C++解法

解法一(追加)

cpp 复制代码
#include <vector>
using namespace std;

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> res;
        res.push_back({});

        // 标准普通for遍历
        for (int k = 0; k < nums.size(); ++k) {
            int num = nums[k];
            int n = res.size();
            for (int i = 0; i < n; ++i) {
                vector<int> temp = res[i];
                temp.push_back(num);
                res.push_back(temp);
            }
        }
        return res;
    }
};

解法二(搜索)

cpp 复制代码
class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> res;
        vector<int> path;
        backtrack(nums, 0, path, res);
        return res;
    }

    void backtrack(vector<int>& nums, int index, vector<int>& path, vector<vector<int>>& res) {
        res.push_back(path);
        for (int i = index; i < nums.size(); ++i) {
            path.push_back(nums[i]);
            backtrack(nums, i + 1, path, res);
            path.pop_back();
        }
    }
};
相关推荐
huzhongqiang6 分钟前
单例装饰器升级:用 jsonic 过滤私有字段
python
张某布响丸辣11 分钟前
Spring AI 极简入门:Java 开发者快速上手 AI 开发
java·人工智能·spring·springai
java1234_小锋13 分钟前
请描述 Spring Boot 的启动流程,包括 SpringApplication 的初始化和 run 方法的核心步骤。
java·数据库·spring boot
疯狂成瘾者15 分钟前
Java 集合 LinkedList 详解:链表结构、常用方法和队列使用
java·开发语言·链表
云梦泽࿐้19 分钟前
变量与数据类型:Python世界的基石
开发语言·python
QK_0021 分钟前
C语言 static 关键字三大作用
c语言·开发语言
lanyxp21 分钟前
Sentinel 管不到 SQL 这一层——我写了个 MyBatis SQL 熔断器
java
隔窗听雨眠22 分钟前
C语言函数递归从入门到精通(下):性能优化与工程实践
c语言·算法·性能优化
开发小能手-roy27 分钟前
Lambda表达式性能陷阱:避坑指南与JIT编译优化分析
开发语言·python