LeetCode题解——78. 子集

题目相关

题目链接

LeetCode中国,https://leetcode-cn.com/problems/subsets/

题目描述

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

说明:解集不能包含重复的子集。

示例

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

题目分析

LeetCode 给出本题难度中等。

题意分析

根据输入的数列,生成所有的子集。很明显,这是一个回溯算法题目。

方案1

样例数据分析

本题的核心就是如何生成子集。也就是说利用回溯算法生成所有的子集。下面我们来分析一下样例数据。样例数据为 [1, 2, 3],数列的长度为 3,那么我们的任务就是如何生成所有的子集。

我们可以考虑使用一个循环来生成子集。什么意思呢,这个循环中,表示从第 i 个位置开始,到数列的结束,依次生成子集。循环代码如下:

for (int i=pos; i<nums.size(); i++) {
    path.push_back(nums[i]);   //加入状态
    dfs(nums, path, i+1);      //进一步搜索
    path.pop_back();           //回溯
}

下面我们用一张图来说明一下对应的输入数据的搜索过程:

从上图,我们可以清晰的看到,如何从空集开始,逐步搜索的过程。

算法设计

参考输入样例数据分析。

搜索函数设计

设计搜索函数的核心就是确定要几个参数。碰到这个问题,我们先不管三七二十一,将函数写上去,然后再逐步确定需要几个参数。这是写回溯算法的套路。

1、一个数组,用来当前的所有数据集。

2、一个数组,用来当前的已经生成的子集。

3、一个整数,表示位置信息,即在所有数据集的索引。

这样,我们就可以设计出一个带有 3 个参数的搜索函数,原型如下。

void dfs(vector<int>& nums, vector<int> path, int pos);

搜索返回条件

这题的返回条件为所有数据搜索完毕。

回溯

套路回溯即可,即套用回溯算法模板即可。

AC 参考代码

class Solution {
public:
    vector<vector<int>> ans;

    /*
    参数1:
    参数2:
    参数3:从pos位置开始选
    */
    void dfs(vector<int>& nums, vector<int> path, int pos) {
        ans.push_back(path);

        for (int i=pos; i<nums.size(); i++) {
            path.push_back(nums[i]);
            dfs(nums, path, i+1);
            path.pop_back();
        }
    }

    vector<vector<int>> subsets(vector<int>& nums) {
        vector<int> path;
        dfs(nums, path, 0);
        
        return ans;
    }
};

方案 2

当然,我们还可以套用标准的回溯模板来实现。也就是搜索的方法不一样,用一个比较容易理解的方法进行搜索,就是每次搜索按个数进行。第一次搜索所有 0 个数字子集,第二次搜索所有 1 个数字子集,第三次搜索所有 2 个数字字节,...,最后一次搜索所有 n 个数据子集。

样例数据分析

这样,我们可以绘制出对应的样例数据搜索过程。

其他地方就不写了,基本是雷同的。

AC 参考代码

class Solution {
public:
    vector<vector<int>> ans;
    int n, k;

    /*
    参数1:
    参数2:
    参数3:从pos位置开始选
    */
    void dfs(vector<int>& nums, vector<int> path, int pos) {
        //退出条件
        if (path.size() == k) {
            //搜索到k个
            ans.push_back(path);
            return;
        }

        for (int i=pos; i<n; i++) {
            path.push_back(nums[i]);
            dfs(nums, path, i+1);
            path.pop_back();
        }
    }

    vector<vector<int>> subsets(vector<int>& nums) {
        n = nums.size();

        vector<int> path;
        for (k=0; k<=n; k++) {
            dfs(nums, path, 0);
        }
        
        return ans;
    }
};

由于这样的搜索 O(n*2^n),所以和第一个方案比对,明显效果差了很多。但是这个方案更加容易理解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力的老周

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值