力扣 子集2 递归回溯法

题目

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的 

子集(幂集)。

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

思路

参考:https://blog.csdn.net/ershiyidian/article/details/139638034?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522172101396816800186570779%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=172101396816800186570779&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-2-139638034-null-null.nonecase&utm_term=%E5%AD%90%E9%9B%86&spm=1018.2226.3001.4450

在递归时,若发现没有选择上一个数,且当前数字与上一个数相同,则可以跳过当前生成的子集。

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

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

    void dfs(bool choosePre, int cur, vector<int>& nums) {
        if (cur == nums.size()) {
            ans.push_back(t);
            return;
        }
        dfs(false, cur + 1, nums);
        if (!choosePre && cur > 0 && nums[cur - 1] == nums[cur]) {
            return;
        }
        t.push_back(nums[cur]);
        dfs(true, cur + 1, nums);
        t.pop_back();
    }

    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        dfs(false, 0, nums);
        return ans;
    }
};

class Solution_wu {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        //结果集合
        vector<vector<int>> sets;
        //每次的子集
        vector<int> subset;
        // 执行回溯算法
        backtrack(0, nums, subset, sets);
        // 返回结果
        return sets;
    }

    // i 表示递归时正在访问的数组元素下标
    // nums 表示当前集合中的元素
    // subset 表示每次递归后生成的子集,就是路径上的那些元素
    // sets 表示最终生成的所有子集合
    void backtrack(int i, vector<int>& nums, vector<int>& subset, vector<vector<int>>& sets) {

        //1、每次确定好一个子集,都把它加入到结果集合中
        sets.push_back(subset);

        // 2、寻找结束条件,由于回溯算法是借助递归实现,所以也就是去寻找递归终止条件
        // 本题中可以不加这个判断,大家可以思考一下为什么可以不加,结合 for 循环的边界来思考
        if (i >= nums.size()) {
            return;
        }

        for (int j = i; j < nums.size(); j++) {
            // 4、判断是否需要剪枝,去判断此时存储的数据是否之前已经被存储过
            if (j > i && nums[j] == nums[j - 1]) {
                continue;
            }
            // 3、把本次递归访问的元素加入到 subset 数组中
            subset.push_back(nums[j]);

            // 5、做出选择,递归调用该函数,进入下一层继续搜索
            // 递归
            backtrack(j + 1, nums, subset, sets);

            // 6、撤销选择,回到上一层的状态
            // 取消对 nums[i] 的选择
            subset.pop_back();

        }
    }
};

int main() {
    Solution a;
    vector<vector<int>> results;
    int num;
    vector<int> nums;
    while (cin >> num) {
        nums.push_back(num);
    }

    results = a.subsetsWithDup(nums);
    cout << results.size() << endl;//测试
    for (int i = 0; i < results.size(); i++) {
        for (int j = 0; j < results[i].size(); j++) {
            cout << results[i][j] << " ";
        }
        cout << endl;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值