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();
        }
    }
};
相关推荐
bzmK1DTbd1 小时前
Swagger API文档:Java RESTful服务的自动生成
java·开发语言·restful
前端之虎陈随易1 小时前
为什么今天还会有新语言?MoonBit 想解决什么问题?
大数据·linux·javascript·人工智能·算法·microsoft·typescript
G.晴天1 小时前
Linux常用命令练习流程
java·linux·运维·服务器·tomcat
risc1234561 小时前
DFA 的运行过程本身就是一种特殊的、空间优化的动态规划
算法·动态规划
仍然.1 小时前
算法题目---字符串
算法
多喝开水少熬夜1 小时前
dfs思路回溯
算法·深度优先·dfs
天真小巫2 小时前
如何找到喜欢做的事(实践版)
职场和发展
veminhe2 小时前
python(五)rag学习一:02向量
python
_F_y2 小时前
仿RabbitMQ实现消息队列-客户端模块实现
c++·算法·rabbitmq