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();
        }
    }
};
相关推荐
Zachery Pole5 小时前
CCF-CSP备战NO.5链表(1)
数据结构·链表
麻瓜生活睁不开眼6 小时前
Android16修改全局桌面视图边框四直角显示为弧边圆角
android·java·深度学习
dear_bi_MyOnly6 小时前
【MyBatis 操作数据库】
java·数据库·学习·mybatis·学习方法
Wang's Blog6 小时前
Go-Zero 项目开发43:基于 Filebeat 收集各个服务的日志信息
开发语言·golang·go-zero·filebeat
2601_953720826 小时前
【计算机毕业设计】基于Spring Boot的心理健康咨询与评测系统的设计与实现
java·spring boot·后端
丈剑走天涯7 小时前
JDK 17 正式特性
java·开发语言
秋田君7 小时前
QT_QFontDialog类字体对话框
开发语言·qt
圣光SG8 小时前
Java操作题练习(七)
java·开发语言·算法
_Jimmy_8 小时前
Agent 溯源精度提升方案
人工智能·python·langchain
麻瓜老宋9 小时前
AI开发C语言应用按步走,表达式计算器calc的第二十三步,多行输入、进制输出、错误恢复、常量折叠、配置加载等
c语言·开发语言·atomcode