上一篇描述了针对数组中没有重复元素进行子集的求取过程递归/回溯:subsets求子集
但是当出现如下数组时:
例如: nums[] = [2, 1, 2, 2]
结果为: [[], [1], [1,2], [1,2,2], [1,2,2,2], [2], [2,2], [2,2,2]]
注意: [2,1,2]与[1,2,2]是重复的集合,则不满足集合的要求。

思考:
同样的递归回溯方式,即每一个元素在是否需要加入到集合中都会有两种状态,存在或者不存在,这里加入的过程中可以对子集进行筛选,如果之前的子集中已经存在有相同的集合,则不需要加入;否则,再将筛选出来的子集加入到最终的集合中。

实现过程如下:
方法一,递归回溯实现

void generate(int i, std::vector<int> &num,std::vector<int> &item,std::vector<std::vector<int>> &result,std::set<std::vector<int>> &uniq_result) {if (i >= num.size()) {return;}item.push_back(num[i]);/*当集合中没有当前item时,则加入最终的子集中*/if (uniq_result.find(item) == uniq_result.end()) { result.push_back(item);uniq_result.insert(item);}generate(i + 1, num, item, result, uniq_result);item.pop_back();generate(i + 1, num, item, result, uniq_result);
}/*method1*/
std::vector<std::vector<int> > get_subsets(std::vector<int> &num) {std::vector<int> item;std::vector<std::vector<int>> result;std::set<std::vector<int> > uniq_result;//维护一个集合sort(num.begin(), num.end());//对初始序列进行排序result.push_back(item);generate(0, num, item, result, uniq_result);return result;
}

方法二,位运算实现

/*method2*/
std::vector<std::vector<int> > get_subsets2(std::vector<int> &num) {std::vector<std::vector<int>> result;std::set<std::vector<int> > uniq_result;int all_set = 1 << num.size();sort(num.begin(), num.end());for (int i = 0;i < all_set; ++i) {std::vector<int> item;for (int j = 0;j < num.size(); ++j) {if (i & (1 << j)) {item.push_back(num[j]);}}/*同样使用集合来判断是否需要加入最终的子集中*/if (uniq_result.find(item) == uniq_result.end()) {result.push_back(item);uniq_result.insert(item);}}return result;
}

测试代码如下:
测试[2,1,2,2]

#include <iostream>
#include <vector>
#include <algorithm>
#include <set>/*
Subsets II已知一组数(其中有重复元素),求这组数可以组成的所有子集。 结果中无重复的子集。
例如: nums[] = [2, 1, 2, 2]
结果为: [[], [1], [1,2], [1,2,2], [1,2,2,2], [2], [2,2], [2,2,2]]
注意: [2,1,2]与[1,2,2]是重复的集合
*/using namespace std;void generate(int i, std::vector<int> &num,std::vector<int> &item,std::vector<std::vector<int>> &result,std::set<std::vector<int>> &uniq_result) {if (i >= num.size()) {return;}item.push_back(num[i]);if (uniq_result.find(item) == uniq_result.end()) {result.push_back(item);uniq_result.insert(item);}generate(i + 1, num, item, result, uniq_result);item.pop_back();generate(i + 1, num, item, result, uniq_result);
}/*method1*/
std::vector<std::vector<int> > get_subsets(std::vector<int> &num) {std::vector<int> item;std::vector<std::vector<int>> result;std::set<std::vector<int> > uniq_result;sort(num.begin(), num.end());result.push_back(item);generate(0, num, item, result, uniq_result);return result;
}/*method2*/
std::vector<std::vector<int> > get_subsets2(std::vector<int> &num) {std::vector<std::vector<int>> result;std::set<std::vector<int> > uniq_result;int all_set = 1 << num.size();sort(num.begin(), num.end());for (int i = 0;i < all_set; ++i) {std::vector<int> item;for (int j = 0;j < num.size(); ++j) {if (i & (1 << j)) {item.push_back(num[j]);}}if (uniq_result.find(item) == uniq_result.end()) {result.push_back(item);uniq_result.insert(item);}}return result;
}int main(int argc, char const *argv[])
{std::vector<int> num;std::vector<int> item;std::vector<std::vector<int>> result;std::vector<std::vector<int>> result2;int tmp;int N;std::cin >> N;for (int i  = 0;i < N; ++i) {std::cin >> tmp;num.push_back(tmp);}result = get_subsets(num);result2= get_subsets2(num);cout << "method1 " << endl;for (int i = 0;i < result.size(); ++i) {if (result[i].size() == 0) {cout << "[]";}for (int j = 0;j < result[i].size(); ++j) {std::cout << "[" << result[i][j] << "] ";}std::cout << std::endl;}cout << "method2 " << endl;for (int i = 0;i < result2.size(); ++i) {if (result2[i].size() == 0) {cout << "[]";}for (int j = 0;j < result2[i].size(); ++j) {std::cout << "[" << result2[i][j] << "] ";}std::cout << std::endl;}   return 0;
}

输出如下:

4
2 1 2 2
method1
[]
[1]
[1] [2]
[1] [2] [2]
[1] [2] [2] [2]
[2]
[2] [2]
[2] [2] [2]
method2
[]
[1]
[2]
[1] [2]
[2] [2]
[1] [2] [2]
[2] [2] [2]
[1] [2] [2] [2]

递归/回溯:Subsets II求子集(有重复元素)相关推荐

  1. 数字拆分问题算法回溯_回溯算法:求子集问题!

    给「代码随想录」一个星标吧! ❝ 认识本质之后,这就是一道模板题 通知:我将公众号文章和学习相关的资料整理到了Github :https://github.com/youngyangyang04/le ...

  2. java数组求子集_回溯算法:求子集问题!

    给「代码随想录」一个星标吧! ❝ 认识本质之后,这就是一道模板题 给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明:解集不能包含重复的子集. 示例: 输入: nums ...

  3. 递归/回溯:Combination Sum II数组之和

    问题如下: 已知一组数(其中有重复元素),求这组数可以组成的所有子集中,子 集中的各个元素和为整数target的子集,结果中无重复的子集. 例如: nums[] = [10, 1, 2, 7, 6, ...

  4. 递归/回溯:subsets求子集

    前言 回溯法又称为试探法,但当探索到某一步时,发现原先选择达不到 目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法. 已知一组数(其中无重复元素),求这组数可以组成的所有子集. 结果中不可 ...

  5. 回溯模板+leetcode——78. 子集 + 90. 子集 II

    回溯法 一般情况下,看到题目要求「所有可能的结果」,而不是「结果的个数」,我们就知道需要暴力搜索所有的可行解了,可以用「回溯法」. 「回溯法」实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻 ...

  6. 回溯---含有相同元素求子集

    含有相同元素求子集 90. Subsets II (Medium) For example, If nums = [1,2,2], a solution is:[[2],[1],[1,2,2],[2, ...

  7. 全排列算法(无重复数字全排列/有重复数字全排列)/ 组合算法/ 求子集算法

    写在前面 全排列 1 无重复数字全排列 1.1 紫书版本 1.2 回溯法 2 有重复数字全排列 复盘易错点(可跳过) 写在前面 很久很久以前就想写的一篇博客,因为懒一直没开工,但是学习全排列算法算是我 ...

  8. Leetcode 129求根节点到叶节点数字之和、104二叉树的最大深度、8字符串转换整数(atoi)、82删除排序链表中的重复元素II、204二分查找、94二叉树的中序遍历、144二叉树的前序遍历

    Top1:Leetcode 129求根节点到叶节点数字之和 官方题解:https://leetcode.cn/problems/sum-root-to-leaf-numbers/solution/qi ...

  9. 算法学习——求有重复元素的全排列(递归)

    算法学习--求有重复元素的全排列(递归) 思路:看到这个题目首先能想到的一点就是:①我们要求元素的所有全排列②我们要对求出的全排列去重 第一步:求全排列,这里先讨论对不含重复元素的数组元素进行全排列, ...

最新文章

  1. MySQL - 多版本控制 MVCC 机制初探
  2. ubuntu系统下Jenkins和tomcat的安装与配置
  3. 相机内参中cx cy_Opencv中的两种去畸变函数
  4. [再寄小读者之数学篇](2014-05-23 递增函数的右极限)
  5. java中计算平均成绩_Java计算平均成绩
  6. 访问控制列表(二)配置命令
  7. 防红直连php,【源码资源】20新PHP网址缩短防封防红短网址生成系统
  8. 03-body标签中相关标签
  9. Java中this关键字的详解
  10. 利用PHP一步解决NAS的Heimdall导航页的内外网切换以及Openwrt等其他局域网ip的跳转
  11. pyqt html编辑器,PyQt笔记——代码编辑器Scintilla的使用方法
  12. UG NX二次开发 - CAM 获取和设置公差的方法,含内外公差、边界内外公差的设置方法
  13. Win10系统开启黑暗主题
  14. unity的C#学习——标识符号、关键字与数据类型及其转换方式
  15. Python基础知识——变量与运算符
  16. 单击选定单元格后输入新内容_Excel表格处理基本操作部分习题参考解答
  17. 两阶段市场投标策略。 电力市场程序。 日前日内竞价 提出了日前电力市场和实时电力市场下充电站的投标策略
  18. 循环神经网络中梯度爆炸的原因
  19. 【VideoQA最新论文阅读】第一篇视频问答综述Video Question Answering: a Survey of Models and Datasets
  20. Maven 是什么东西?

热门文章

  1. Android系统手机端抓包方法
  2. asp.net httpmodule 访问页面控件 备忘
  3. 为 区域添加 Tag
  4. 基于jQuery垂直多级导航菜单代码
  5. CSS实现网页图片预加载
  6. 域名删除时间及whois状态说明
  7. ProxyError: Conda cannot proceed due to an error in your proxy configuration
  8. java基于http协议编程_Java中基于HTTP协议网络编程
  9. 《OpenCV3编程入门》学习笔记5 Core组件进阶(六)输入输出XML和YAML文件
  10. 程序员笔试面试后上机_2021年国考笔试成绩查询后,面试准备阶段需要做好四方面...