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();
        }
    }
};
相关推荐
Yang_jie_031 分钟前
笔记:数据结构(顺序表)
数据结构·windows·笔记
Metaphor69211 分钟前
使用 Python 在 Word 文档中添加批注
python·word
FreakStudio18 分钟前
WIZnet 开源方案分享:W55MH32 开发板 + 小智 AI实现以太网版本的小智机器人
python·单片机·嵌入式·大学生·面向对象·并行计算·电子diy·电子计算机
栈溢出了18 分钟前
Java Lambda 表达式笔记
java·开发语言·intellij-idea
会周易的程序员20 分钟前
使用 pybind11 封装 C++ 日志库 microLog 为 Python 模块
java·c++·python·物联网·架构·日志·aiot
zhixingheyi_tian28 分钟前
一份GC日志的解读
java·开发语言
czhaii28 分钟前
串口1中断收发-C语言-MODBUS协议
c语言·开发语言
ywl47081208738 分钟前
ArrayList和LinkedList内部的实现原理和区别
java·java基础
一只专注api接口开发的技术猿44 分钟前
电商评论自动化监控与情感数据分析完整落地教程(附可直接运行 Python 代码)
大数据·数据库·python·数据分析·自动化
Fox爱分享1 小时前
字节二面:1000瓶酒,有一瓶是毒药,多少只老鼠可以查出来?
算法·面试·程序员