200.回溯算法:子集||(力扣)

cpp 复制代码
class Solution {
public:
    vector<int> res;                // 当前子集
    vector<vector<int>> result;     // 存储所有子集

    void backtracing(vector<int>& nums, int index, vector<bool>& used) {
        result.push_back(res);      // 将当前子集加入结果

        for (int i = index; i < nums.size(); i++) {
            // 跳过重复元素
            if (i > 0 && nums[i] == nums[i - 1] && used[i - 1]==false) {
                continue;
            }

            res.push_back(nums[i]);  // 将当前元素加入子集
            used[i] = true;          // 标记当前元素已使用

            backtracing(nums, i + 1, used); // 递归生成后续子集

            used[i] = false;         // 取消标记,回溯
            res.pop_back();          // 从子集中移除当前元素,回溯
        }
    }

    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        vector<bool> used(nums.size(), false);  // 标记数组元素是否被使用
        sort(nums.begin(), nums.end());         // 排序数组以便于去重
        backtracing(nums, 0, used);             // 调用回溯函数开始生成子集
        return result;                          // 返回所有生成的子集
    }
};

主函数调用

  1. subsetsWithDup 函数 :
    • 输入 nums = {1, 2, 2}
    • 初始化 used = {false, false, false}
    • nums 进行排序(尽管已经排好序了),结果 nums = {1, 2, 2}
    • 调用 backtracing(nums, 0, used)

回溯函数执行

  1. 第一次调用 backtracing(nums, 0, used):

    • index = 0
    • 当前子集 res = {}
    • 当前结果 result = {``{}}

    循环1(i = 0):

    • nums[0] = 1 未使用
    • res.push_back(1) -> res = {1}
    • used[0] = true
    • 调用 backtracing(nums, 1, used)
  2. 第二次调用 backtracing(nums, 1, used):

    • index = 1
    • 当前子集 res = {1}
    • 当前结果 result = {``{}, {1}}

    循环1(i = 1):

    • nums[1] = 2 未使用
    • res.push_back(2) -> res = {1, 2}
    • used[1] = true
    • 调用 backtracing(nums, 2, used)
  3. 第三次调用 backtracing(nums, 2, used):

    • index = 2
    • 当前子集 res = {1, 2}
    • 当前结果 result = {``{}, {1}, {1, 2}}

    循环1(i = 2):

    • nums[2] = 2 未使用
    • res.push_back(2) -> res = {1, 2, 2}
    • used[2] = true
    • 调用 backtracing(nums, 3, used)
  4. 第四次调用 backtracing(nums, 3, used):

    • index = 3
    • 当前子集 res = {1, 2, 2}
    • 当前结果 result = {``{}, {1}, {1, 2}, {1, 2, 2}}
    • 结束条件 index >= nums.size() 达成,返回上一层

    回溯:

    • res.pop_back() -> res = {1, 2}
    • used[2] = false
    • 返回上一层
  5. 回到第三次调用 backtracing(nums, 2, used):

    • 当前子集 res = {1, 2}
    • 当前结果 result = {``{}, {1}, {1, 2}, {1, 2, 2}}

    回溯:

    • res.pop_back() -> res = {1}
    • used[1] = false

    循环2(i = 2):

    • nums[2] = 2 未使用,且 nums[2] == nums[1],但 used[1] == false,跳过
    • 返回上一层
  6. 回到第二次调用 backtracing(nums, 1, used):

    • 当前子集 res = {1}
    • 当前结果 result = {``{}, {1}, {1, 2}, {1, 2, 2}}

    回溯:

    • res.pop_back() -> res = {}
    • used[0] = false

    循环2(i = 1):

    • nums[1] = 2 未使用
    • res.push_back(2) -> res = {2}
    • used[1] = true
    • 调用 backtracing(nums, 2, used)
  7. 第五次调用 backtracing(nums, 2, used):

    • index = 2
    • 当前子集 res = {2}
    • 当前结果 result = {``{}, {1}, {1, 2}, {1, 2, 2}, {2}}

    循环1(i = 2):

    • nums[2] = 2 未使用
    • res.push_back(2) -> res = {2, 2}
    • used[2] = true
    • 调用 backtracing(nums, 3, used)
  8. 第六次调用 backtracing(nums, 3, used):

    • index = 3
    • 当前子集 res = {2, 2}
    • 当前结果 result = {``{}, {1}, {1, 2}, {1, 2, 2}, {2}, {2, 2}}
    • 结束条件 index >= nums.size() 达成,返回上一层

    回溯:

    • res.pop_back() -> res = {2}
    • used[2] = false
    • 返回上一层
  9. 回到第五次调用 backtracing(nums, 2, used):

    • 当前子集 res = {2}
    • 当前结果 result = {``{}, {1}, {1, 2}, {1, 2, 2}, {2}, {2, 2}}

    回溯:

    • res.pop_back() -> res = {}
    • used[1] = false
    • 返回上一层
  10. 回到第一次调用 backtracing(nums, 0, used):

    • 当前子集 res = {}
    • 当前结果 result = {``{}, {1}, {1, 2}, {1, 2, 2}, {2}, {2, 2}}

    循环3(i = 2):

    • nums[2] = 2 未使用,且 nums[2] == nums[1],但 used[1] == false,跳过
  11. 结束

相关推荐
vibecoding日记2 小时前
双非如何快速入职字节等大厂大模型?真实案例分析:推理优化和投机解码
算法·求职·大模型工程师
yszaygr21384 小时前
Verilog参数化游程编码RLE模块
算法
望易5 小时前
刚设计的大模型架构-双域耦合认知框架
算法·架构
复杂网络9 小时前
多个 Claude Code 与多个 Codex 协同工作:设计与实现方案
算法
HjhIron1 天前
面试常客:字符串算法从入门到进阶
算法·面试
吴佳浩1 天前
DeepSeek DSpark:Confidence-Scheduled Speculative Decoding 技术解析
人工智能·算法·deepseek
触底反弹1 天前
🧠 搞懂 Token,才算真正入门大模型——从分词原理到 Embedding 语义实战
javascript·人工智能·算法
vivo互联网技术1 天前
ICLR 2026 | 基于后验采样的图像恢复方法LearnIR:人脸去阴影、去雾
人工智能·算法·aigc
浮生望1 天前
JS字符串与回文算法:从包装类到双指针的面试进阶之路
javascript·算法
黄敬峰1 天前
面试必刷:从JS底层包装类到双指针,彻底搞懂字符串与回文算法
算法