子集系列(二) 满足特定要求的子集,例 [LeetCode] Combination, Combination Sum I, II

引言

既上一篇 子集系列(一) 后,这里我们接着讨论带有附加条件的子集求解方法。

这类题目也是求子集,只不过不是返回所有的自己,而往往是要求返回满足一定要求的子集。

解这种类型的题目,其思路可以在上一篇文章的思路略作改进。

例 1,求元素数量为定值的所有子集

Combinations

Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.

For example,
If n = 4 and k = 2, a solution is:

[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]
class Solution {
public:
    vector<vector<int> > combine(int n, int k) {
    }
}

思路1:这道题本质上就是求 [1,2,...n] 这个集合中,个数为k的所有子集。

利用上篇文章的思路:每一个元素,在子集中都有两种可能:出现 OR 不出现。我们只要将两种情况都判断一下,看当前子集是否满足要求就好,在本题中,需要满足的要求是:size == k

class Solution {
public:
    vector<vector<int> > combine(int n, int k) {
        if(n < k) return res;
        combineCore(1, n, k);
        return res;
    }
private:
    vector<int> path;
    vector<vector<int> > res;
    void combineCore(int st, int n, int k){
        if(path.size() == k){
            res.push_back(path);
            return;
        }
        if(st > n) return;
        combineCore(st+1, n, k); //case1: skip
        path.push_back(st);
        combineCore(st+1, n, k); //case2: not skip
        path.pop_back();
    }
};

AC 52ms。

思路2:当然也可以用回溯思想来做:选择子集的第一个数时,可以在 [1,2,...,n-(k-1)] 这么多数中选择,选好了第一个数后,假定选的是q,那么子集的第二个数就只能从 [q+1, q+2, .... , n-(k-2)]这些数中选了。

因此递归函数中,每次递进一次递归,k就减1,表示子集中待确定的数字越来越少,同时,要有一个参数来表示可选范围的起始元素,假设为st。

代码:

class Solution {
public:
    vector<vector<int> > combine(int n, int k) {
        if(n < k) return res;
        vector<int> v;
        combineCore(1, n, k, v);
        return res;
    }
private:
    vector<vector<int> > res;
    void combineCore(int st, int n, int k, vector<int> &v){
        if(k == 0){
            res.push_back(v);
            return;
        }
        for(int i = st; i <= n-k+1; ++i){
            v.push_back(i);
            combineCore(i+1, n, k-1, v);
            v.pop_back();
        }
    }
};

AC 48ms。

例 2.1,求元素和为定值的所有子集

Combination Sum

Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.

The same repeated number may be chosen from C unlimited number of times.

Note:

  • All numbers (including target) will be positive integers.
  • Elements in a combination (a1, a2, … , ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak).
  • The solution set must not contain duplicate combinations.

For example, given candidate set 2,3,6,7 and target 7
A solution set is: 
[7] 
[2, 2, 3]

class Solution {
public:
    vector<vector<int> > combinationSum(vector<int> &candidates, int target) {
    }
};

思路:依然从每一个元素有 出现 OR 不出现入手,注意题意:一个元素可以不被用或者使用多次。

我们可以先将candidates排序,然后去重。在这样的candidates基础上,我们考虑完“出现”的情况后,st不需要后移一位。

class Solution {
public:
    vector<vector<int> > combinationSum(vector<int> &candidates, int target) {
        if(target <= 0) return res;
        if(candidates.size() == 0) return res;
        sort(candidates.begin(), candidates.end());    //排序
        if(candidates.size() > 1){ //去重
            int p = 0, q = 1;
            while(q < candidates.size()){
                if(candidates[p] != candidates[q]){
                    candidates[++p] = candidates[q++];
                }else{
                    ++q;
                }
            }
            candidates.erase(candidates.begin()+p+1, candidates.end());
        }
        combinSumCore(candidates, 0, target);
        return res;
    }
private:
    vector<int> path;
    vector<vector<int> > res;
    void combinSumCore(vector<int> &candidates, int st, int target) {
        if(target == 0){
            res.push_back(path);
            return;
        }
        if(target < 0 || st >= candidates.size() || candidates[st] > target) return;
        combinSumCore(candidates, st+1, target); //case1: skip
        path.push_back(candidates[st]);
        combinSumCore(candidates, st, target - candidates[st]); //case2: not skip,但是st这里不+1,因为数可以被用多次。
        path.pop_back();
    }
};

AC 60ms

例 2.2,求元素和为定值的所有子集

和例2.1同样的题目,不同的是一个元素只能用一次。

Combination Sum II

Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.

Each number in C may only be used once in the combination.

Note:

  • All numbers (including target) will be positive integers.
  • Elements in a combination (a1, a2, … , ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak).
  • The solution set must not contain duplicate combinations.

For example, given candidate set 10,1,2,7,6,1,5 and target 8
A solution set is: 
[1, 7] 
[1, 2, 5] 
[2, 6] 
[1, 1, 6]

class Solution {
public:
    vector<vector<int> > combinationSum2(vector<int> &num, int target) {}
};

思路:题目中num中包含重复元素,每个元素只能用一次。

我们依然先将num排序,那么重复的元素肯定在一起了。对于这些重复的元素,单独提出来考虑,因为对于这种元素,其 “出现 OR 不出现”的问题不单单和整体条件有关(这里的整体条件是和为target),而且和其相邻元素有关。

以[1,2,2,2,3]为例,我们单独将其中的[2,2,2] 部分提出来考虑,这部分的组合只能是: [], [2], [2,2], [2,2,2]。

class Solution {
public:
    vector<vector<int> > combinationSum2(vector<int> &num, int target) {
        if(num.size() == 0) return res;
        sort(num.begin(), num.end());
        combinationSumCore(num, 0, target);
        return res;
    }
private:
    vector<int> path;
    vector<vector<int> > res;
    void combinationSumCore(vector<int> &num, int start, int target) {
        if(target < 0) return;
        if(target == 0){
            vector<int> v;
            res.push_back(path);
            return;
        }
        if(start < num.size()){
            int i = start+1;
            for(; i < num.size() && num[start] == num[i]; ++i);
            combinationSumCore(num, i, target);//case1: Jump 掉相同的

            int sum = 0, j = i-1;
            for(; j >= start; --j){
                sum += num[j];
                path.push_back(num[j]);
                combinationSumCore(num, i, target - sum);//case2: 这段相同段上的所有使用情况。
            }
            for(j = i-1; j >= start; --j){
                path.pop_back();
            }
        }
    }
};

AC 96ms

结语

有不少问题其实都可以转化为求子集的情况,只不过子集需要满足一定的条件。

对于这种问题,通过递归实现 每一个元素的“出现OR不出现” 两种情况,可以作为一种思路。

时间: 2024-08-11 09:39:53

子集系列(二) 满足特定要求的子集,例 [LeetCode] Combination, Combination Sum I, II的相关文章

Subsets 子集系列问题 leetcode

子集系列问题: Coding 问题中有时会出现这样的问题:给定一个集合,求出这个集合所有的子集(所谓子集,就是包含原集合中的一部分元素的集合). 或者求出满足一定要求的子集,比如子集中元素总和为定值,子集元素个数为定值等等. 我把它们归类为子集系列问题. leetcode上原题链接: 思路分析: 思路一 可以用递推的思想,观察S=[], S =[1], S = [1, 2] 时解的变化. 可以发现S=[1, 2] 的解就是 把S = [1]的所有解末尾添上2,然后再并上S = [1]里面的原有解

ASP.NET MVC学习系列(二)-WebAPI请求

继续接着上文 ASP.NET MVC学习系列(一)-WebAPI初探 来看看对于一般前台页面发起的get和post请求,我们在Web API中要如何来处理. 这里我使用Jquery 来发起异步请求实现数据调用. 继续使用上一文章中的示例,添加一个index.html页面,添加对jquery的引用. 一.无参数Get请求 一般的get请求我们可以使用jquery提供的$.get() 或者$.ajax({type:"get"}) 来实现: 请求的后台Action方法仍为上篇文章中的GetU

windows下mongodb基础玩法系列二CURD操作(创建、更新、读取和删除)

windows下mongodb基础玩法系列 windows下mongodb基础玩法系列一介绍与安装 windows下mongodb基础玩法系列二CURD操作(创建.更新.读取和删除) 简单说几句 在mongodb中3元素:db(数据库).collection(集合).document(文档) 其中collection类似于数据库中的表,document类似于行,这样一来我们就将内容对比起来记忆学习了. 数据格式 MongoDB documents是BSON格式(一种类json的一种二进制形式的存

Exchange Server 2013系列二:服务器角色

杜飞 在上一篇文章中,我们提到现在硬件性能的增加以及成本的下降,硬件已经不再成为软件应用的约束因素,特别是CPU,其 计算能力的成本显著降低.Exchange 2013 的主要设计目标是简化缩放.提高硬件利用率和实现故障隔离.Exchange 2013一开始将服务器角色的数目减少到了两个:客户端访问服务器角色和邮箱服务器角色,当然,升级到SP1之后也包含边缘服务器角色或者是边界网络中安装 Exchange 2007 或 Exchange 2010 边缘传输服务器角色.如下图所示: 客户端访问服务

WPF入门教程系列二——Application介绍

原文:WPF入门教程系列二--Application介绍 一.Application介绍 WPF和WinForm 很相似, WPF与WinForm一样有一个 Application对象来进行一些全局的行为和操作,并且每个 Domain (应用程序域)中仅且只有一个 Application 实例存在.和 WinForm 不同的是WPF Application默认由两部分组成 : App.xaml 和 App.xaml.cs,这有点类似于 Asp.Net WebForm,将定义和行为代码相分离. 微

SQL Server 2008空间数据应用系列二:空间索引(Spatial Index)基础

原文:SQL Server 2008空间数据应用系列二:空间索引(Spatial Index)基础 在前一篇博文中我们学习到了一些关于地理信息的基础知识,也学习了空间参照系统,既地球椭球体.基准.本初子午线.计量单位.投影等相关理论知识,我们可以使用这些空间参照系统组件来定义一系列应用于地球空间上的几何图像来表示地理空间中的特定功能,表示着地球上一个一个特定的位置点. 本篇主要介绍地理空间索引的概念以及微软SQL Server 2008 R2中的空间索引的应用. 一.空间索引 空间索引是指依据空

ldap配置系列二:jenkins集成ldap

ldap配置系列二:jenkins集成ldap jenkins简介 jenkins是一个独立的.开放源码的自动化服务器,它可以用于自动化与构建.测试.交付或部署软件相关的各种任务. jenkins官方文档: https://jenkins.io/doc/ jenkins安装 jenkins下载地址: https://jenkins.io/download/ # jdk1.8下载 [[email protected]_0_15_centos local]# wget http://download

highcharts 结合phantomjs纯后台生成图片系列二之php2

上篇文章中介绍了phantomjs的使用场景,方法. 本篇文章详细介绍使用php,highcharts 结合phantomjs纯后台生成图片.包含一步步详细的php代码 一.highcharts 结合phantomjs纯后台生成图片系列的准备: 下载phantomjs解析插件,从highcharts官方下载所需插件. 新建一个工程文件夹phantomjs,所必备的js文件有: highcharts 结合phantomjs纯后台生成图片系列二之php 其中jquery.js为 v1.7.1; hi

iOS开发UINavigation系列二——UINavigationItem

iOS开发UINavigation系列二--UINavigationItem 一.引言 UINavigationItem是导航栏上用于管理导航项的类,在上一篇博客中,我们知道导航栏是通过push与pop的堆栈操作来对item进行管理的,同样,每一个Item自身也有许多属性可供我们进行自定制.这篇博客,主要讨论UINavigationItem的使用方法. UINavigationBar:http://my.oschina.net/u/2340880/blog/527706. 二.来说说UINavi