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

同样之前有类似的相关的问题递归/回溯:Subsets II求子集(有重复元素),最终将子集中和为8的集合输出,同样不能有重复子集

一个直接的办法就是在输出最终子集的时候,使用之前类似的问题解决过程,将初始筛选的集合做一个计算,检查是否满足target 为8的要求,满足则返回。
类似如下:

std::vector<std::vector<int> > get_subsets(std::vector<int> &num ,int target) {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);/*对递归回溯获取到的结果进行计算,将满足要求的和为target的子集筛选出来返回*/int sum; std::vector<std::vector<int>> target_result;for (int i = 0; i< result.size(); ++i){sum = 0;for (int j = 0; j < result[i].size(); ++j) {sum += result[i][j];}if (sum == target) {target_result.push_back(result[i]);}}return target_result;
}

但是一个很严重的问题,递归/回溯本身是2^n的复杂度,如果仍然按照以上的方法对所有元素筛选一遍之后再返回显然时间复杂度极高,并且在回溯过程中没有应用到要求的target条件

提出如下方法,在回溯的过程中进行计算,当计算过程中有超过target的集合或者元素,即可终止继续递归,直接回溯,防止没有意义的递归下去。
类似[10,1,2,3,5],其中包含10的子集显然没有必要加入到最终的集合,因为10已经大于target了

实现算法如下:

oid generate(int i, std::vector<int> &num,std::vector<int> &item,std::vector<std::vector<int> > &result,std::set<std::vector<int> > &uniq_result,int sum, int target) {/*当结果大于target,直接返回,没有必要继续递归*/if (sum > target || i >= num.size()) {return;}sum += num[i];item.push_back(num[i]);/*满足结果为target,且不是重复子集,则加入到最终的结果中*/if (sum == target && uniq_result.find(item) == uniq_result.end()) {result.push_back(item);uniq_result.insert(item);}generate(i + 1, num, item, result, uniq_result, sum, target);item.pop_back();sum -= num[i];generate(i + 1, num, item, result, uniq_result, sum, target);
}std::vector<std::vector<int> > get_combiname_sets(std::vector<int> &num, int target) {std::vector<int> item;std::vector<std::vector<int>> result; //存储最终的子集std::set<std::vector<int> > uniq_result; //集合,筛选重复子集sort(num.begin(),num.end());generate(0, num, item, result, uniq_result, 0, target);return result;
}

测试代码如下:
nums[] = [10, 1, 2, 7, 6, 1, 5], target = 8

#include <iostream>
#include <vector>
#include <algorithm>
#include <set>/*
已知一组数(其中有重复元素),求这组数可以组成的所有子集中,子 集中的各个元素和为整数target的子集,结果中无重复的子集。
例如: nums[] = [10, 1, 2, 7, 6, 1, 5], target = 8
结果为: [[1, 7], [1, 2, 5], [2, 6], [1, 1, 6]]
*/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,int sum, int target) {if (sum > target || i >= num.size()) {return;}sum += num[i];item.push_back(num[i]);if (sum == target && uniq_result.find(item) == uniq_result.end()) {result.push_back(item);uniq_result.insert(item);}generate(i + 1, num, item, result, uniq_result, sum, target);item.pop_back();sum -= num[i];generate(i + 1, num, item, result, uniq_result, sum, target);
}std::vector<std::vector<int> > get_combiname_sets(std::vector<int> &num, int target) {std::vector<int> item;std::vector<std::vector<int>> result;std::set<std::vector<int> > uniq_result;sort(num.begin(),num.end());generate(0, num, item, result, uniq_result, 0, target);return result;
}int main(int argc, char const *argv[])
{std::vector<int> num;std::vector<int> item;std::vector<std::vector<int>> result;int tmp;int N;std::cin >> N;for (int i  = 0;i < N; ++i) {std::cin >> tmp;num.push_back(tmp);}int target;cin >> target;result= get_combiname_sets(num,target);for (int i = 0;i < result.size(); ++i) {for (int j = 0;j < result[i].size(); ++j) {std::cout << "[" << result[i][j] << "] ";}std::cout << std::endl;}return 0;
}

输出如下:

#输入
7
10 1 2 7 6 1 5
8#结果
[1] [1] [6]
[1] [2] [5]
[1] [7]
[2] [6]

总结:
递归回溯的结合,本身是时间复杂度较高的一种算法实现组合,但是如果能够合理运用给出的筛选条件,能够极大得缩短时间复杂度,使得代码更加简介高效。

递归/回溯:Combination Sum II数组之和相关推荐

  1. 递归/回溯:Subsets II求子集(有重复元素)

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

  2. 40. Combination Sum II 组合总和 II

    给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. candidates 中的每个数字在每个组合中只能使用一次. ...

  3. Combination Sum 和Combination Sum II

    这两道题的基本思路和combination那一题是一致的,也是分治的方法. 其中combination Sum复杂一点,因为每个数可能用多次.仔细分析下,本质上也是一样的.原来是每个数仅两种可能.现在 ...

  4. C#LeetCode刷题之#40-组合总和 II(Combination Sum II)

    目录 问题 示例 分析 问题 该文章已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3666 访问. 给定一个数组 candidates ...

  5. 40. Combination Sum II **

    description: 给定target, 求给定数列中找到几个数(其中的数不可以重复使用,且一组数有几个也不做限制)的和为target,和上面那个题一毛一样的,就改一下下标就行了,背下来背下来背下 ...

  6. 40. Combination Sum II

    避免这个循环的重复 所以i>position && nums[i] == nums[i-1] 1 class Solution { 2 List<List<Integ ...

  7. Combination Sum II

    1 解析 这道题是则就是上一道题的进阶版,此题可以出现相同的元素,例如[1 1 1 7] 目标值为8,那么难点就在于如何去除重复的情况,只保留[1 7]这种情况. 2 思路 都是采用DFS求解,思路和 ...

  8. 【DFS】LeetCode 40. Combination Sum II

    Solution1:我的答案 同39题.DFS时间复杂度O(2n)O(2n)O(2^n),空间复杂度O(kn)O(kn)O(kn),k是最终答案的数量,n是元素个数 去重,用set,比较偷懒的做法 c ...

  9. LeetCode40 Combination Sum II 解析

    详细见:leetcode.com/problems/combination-sum-ii C和Python的去重算法,应该记住. Java是很久之前写的,并不好. 规则是:相同数字. 1,前面选了,后 ...

最新文章

  1. 计算机软件打开为什么跑一边,为什么打开Excel后开始菜单就跑掉了?
  2. 新建Acquisition contract出错的问题
  3. pwd 查看”当前工作目录“的完整路径
  4. Nplayer本地文件拷到服务器,手把手教你简易NAS构建,手机/平板/智能电视随意调取,家庭存储云共享,有了自己的网络云盘后再也不用担心容量不够了!...
  5. import是引进外部函数吗_vue3已正式发布,你学了吗
  6. SpringBoot + AOP 统一处理日志
  7. Python图像处理库PIL的ImageStat模块介绍
  8. (9)Zynq UART控制器介绍
  9. 30岁前挣到10万年薪 五位年轻人的高薪秘诀
  10. 第三节:python 交互和调用参数
  11. matlab欧式期权定价公式,[转载]期权定价的Matlab实现(以欧式看涨期权为例)
  12. python二级考试操作题6答案_python二级考试试题6
  13. Ubuntu下安装Genymotion安卓模拟器
  14. java开发app_使用java制作app教程
  15. android手机大小,安卓手机内存多大才够用?如何选择内存的大小
  16. 【iOS】Plist-XML-JSON数据解析
  17. 大地水准面 地球椭球体 大地基准面 地图投影理解
  18. 【阿里云仓库 可用 2022】IDEA MAVEN setings.xml 配置
  19. strip()函数用法简介
  20. dev c++ 学习C语言+快捷键

热门文章

  1. Notification和KVO有什么不同
  2. msvcrt.lib和LIBCD.lib链接冲突
  3. Hadoop学习笔记一 简要介绍
  4. c语言的求素数算法,C语言求素数的算法
  5. java basicstroke_使用java.awt.BasicStroke动画化虚线
  6. window mysql 字符集_Windows mysql默认字符集修改
  7. TCP协议的服务器与客户端的程序设计(代码注释超详细)
  8. 崇阳计算机技校,湖北省崇阳县龙翔技工学校
  9. 隔年增长的题_行测资料分析:一起聊聊隔年增长
  10. asp.net webform 复制窗体代码_逆向分析流氓软件自我复制以及防御思路