题目描述:

给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的数字可以无限制重复被选取。

说明:

  • 所有数字(包括 target)都是正整数。
  • 解集不能包含重复的组合。

示例 1:

输入: candidates = [2,3,6,7], target = 7,
所求解集为:
[
[7],
[2,2,3]
]

示例 2:

输入: candidates = [2,3,5], target = 8,
所求解集为:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
]

要完成的函数:

vector<vector<int>> combinationSum(vector<int>& candidates, int target)

说明:

1、这道题给定一个vector,里面装着彼此不重复的元素,元素是正整数,还给了一个target,也是正整数。

要求找出各种有可能的组合,使得vector中的元素的和等于target。

每个组合存储在一个一维的vector中,最终把这些一维的vector存在二维的vector中,返回二维vector。

各个组合不能重复。

2、我们先来看一个例子,vector是[2,3,6,7],target是7,我们人类怎么解决这个问题呢?

我们当然是从后面看起,最大的7,看能不能满足target,结果是可以的,那么我们再看前一个数6。

6小于等于7,我们还要一个1,往本身或者前面看有没有小于等于1的,结果没有,那么我们就没有办法搭配6了,我们再看前一个数3。

3小于等于7,我们还要4,本身还可以再减去3,那么还要一个1,再往本身或者前面看,没有1。

那我们也许可以不要第二次减去3,我们减去前一个数2,然后还要一个2,刚好本身可以满足。

然后再看前一个数2,本身还可以再减去2,然后本身还可以再减去2,然后还要一个1,但没有办法了。

所以最终我们得到的组合是[[7],[3,2,2]]。

做的题目比较多的同学,可能已经嗅到了一股递归的味道。

这道题就是要不断试探,试探可以满足target的,插入到二维vector中,试探到不可以满足的,回退一步,再试其他可能。

代码如下:(附详解)

    vector<vector<int>>res;//全局变量,最终要返回的二维vector
vector<int>res1;//全局变量,存储每次可能的组合结果
void digui(vector<int>& candidates,int index,int target,vector<int>& res1)
{
if(target==0)//退出条件
{
res.push_back(res1);//存储到二维vector中
return;
}
while(index>=0)//不断地试探
{
if(candidates[index]<=target)//如果可以减去
{
res1.push_back(candidates[index]);//进入递归前,设置一下res
digui(candidates,index,target-candidates[index],res1);
res1.pop_back();//退出递归,恢复一下res
}
index--;//index-1,试探前一个数值
}
if(index<=0)//如果index==-1,那么只能返回了
return; }
vector<vector<int>> combinationSum(vector<int>& candidates, int target)
{
int s1=candidates.size();
digui(candidates,s1-1,target,res1);//直接进入递归
return res;
}

上述代码在递归那个部分,可能有些同学还不太清晰,可以自己手写一下推导的过程,逻辑会更加清晰。

【 再啰嗦两句,理解逻辑的同学可以不用看了】

其实vector比如[2,3,6,7],我们可以粗略地看成外层的递归和内层的递归。外层递归比如第一次试探了7,刚刚好。

接着循环迭代到前一个数6,可以减去,然后进入内层递归,不能再减去本身6了,所以循环迭代到前一个数3,也还是不能,所以循环迭代到前一个数2,也还是不能,然后结束内层递归。

接着循环迭代到前一个数3,可以减去,然后进入内层递归,可以减去本身3,再进入深一层的内层递归,不能再减去3了,循环迭代到前一个数2,也不能,结束深一层的内层递归,返回内层递归,我们不减去3,直接减去2,进入深一层的内层递归,可以减去本身2,那么结束深一层的内层递归,同时vector到头部了,结束内层递归。

接着循环迭代到前一个数2,可以减去,然后进入内层递归,可以减去本身2,进入深一层的内层递归,可以减去本身2,进入再深一层的内层递归,不能再减去2了,于是退出再深一层的内层递归,再退出深一层的内层递归,再退出内层递归。

接着……前面没有数了,结束外层递归。

我们会发现其实外层递归和内层递归的处理逻辑是一样的,都是不断地试探,所以我们可以统一写成一种形式。

上述代码实测12ms,beats 98.16% of cpp submissions。

leetcode-39-组合总和(有趣的递归)的更多相关文章

  1. [leetcode] 39. 组合总和(Java)(dfs、递归、回溯)

    39. 组合总和 直接暴力思路,用dfs+回溯枚举所有可能组合情况.难点在于每个数可取无数次. 我的枚举思路是: 外层枚举答案数组的长度,即枚举解中的数字个数,从1个开始,到target/ min(c ...

  2. Java实现 LeetCode 39 组合总和

    39. 组合总和 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. candidates 中的数字 ...

  3. [LeetCode] 39. 组合总和

    题目链接 : https://leetcode-cn.com/problems/combination-sum/ 题目描述: 给定一个无重复元素的数组 candidates 和一个目标数 target ...

  4. leetcode 39 组合总和 JAVA

    题目: 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. candidates 中的数字可以无限制 ...

  5. LeetCode 39. 组合总和(Combination Sum)

    题目描述 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. candidates 中的数字可以无限 ...

  6. leetcode 39. 组合总和(python)

    给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. candidates 中的数字可以无限制重复被选 ...

  7. LeetCode——39. 组合总和

    给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. candidates 中的数字可以无限制重复被选 ...

  8. 【LeetCode】39. 组合总和

    39. 组合总和 知识点:递归:回溯:组合:剪枝 题目描述 给定一个无重复元素的正整数数组 candidates 和一个正整数 target ,找出 candidates 中所有可以使数字和为目标数  ...

  9. LeetCode 中级 - 组合总和II(105)

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

  10. Leetcode 377.组合总和IV

    组合总和IV 给定一个由正整数组成且不存在重复数字的数组,找出和为给定目标正整数的组合的个数. 示例: nums = [1, 2, 3] target = 4 所有可能的组合为: (1, 1, 1, ...

随机推荐

  1. 阿里云自定义监控tomcat进程数

    阿里云提供自定义监控SDK,这有助于我们定制化的根据自身业务来做监控,下面我就根据业务需求来介绍一个简单的自定义监控配置. 阿里提供了2个版本的自定义监控接口:自定义监控SDK(python版) :c ...

  2. curl模拟多线程抓取网页(优化)

    通过上篇文章清楚了通过curl_multi_*函数可以一次请求多个url,但是也留下了问题,就是结果要等所有数据请求结束一起返回,才能逐个处理数据.优化代码,使先成功请求的url先返回处理结果,而不是 ...

  3. Halcon阈值化算子dual_threshold和var_threshold的理解

    Halcon中阈值二值化的算子众多,通常用得最多的有threshold.binary_threshold.dyn_threshold等. threshold是最简单的阈值分割算子,理解最为简单:bin ...

  4. ESXi系统命令行下启动虚拟机

    从命令行启动虚拟机: 用命令列出虚拟机的ID:vim-cmd vmsvc/getallvms |grep <vm name>注意: 第一列输出是vmid. 用命令查看虚拟机启动状态:vim ...

  5. JQuery 对象和事件

    JQuery 对象和事件 一:JQuery 对象和 Dom 对象 在使用 JQuery 过程中,我们一般(也是绝大多数情况下,除非我们使用了第二个框架)只有两类对象,即:JQuery 对象和 Dom ...

  6. Linux服务器上日志报com.mysql.jdbc.PacketTooBigException: Packet for query is too large (1783 > 1024). You can change this value on the server by setting the max_allowed_packet' variable.

    在做查询数据库操作时,报了以上错误,还有out of memery heap hacp ,原因是MySQL的max_allowed_packet设置过小引起的,我一开始设置的是1M,后来改为了20M ...

  7. win7搭建node+npm+bower的环境

    原文的地址:https://my.oschina.net/JeeChou/blog/219699 Windows下的NodeJS安装是比较方便的(v0.6.0版本之后,支持windows native ...

  8. Webservice初级问题: FAILED TO READ WSDL document

    这个问题是说明,这个版本的没法下载 犯错的图样 处理方法一: 将网页上xml文档下载,保存在本地,然后错误提示的这几行删除,保存文档,然后从本地调用 (1)右键另存为 保存为文件名a.xml (2)打 ...

  9. rinetd小记

    官网:http://www.boutell.com/rinetd/ 下载地址:http://www.boutell.com/rinetd/http/rinetd.tar.gz 编译安装: 对于Wind ...

  10. Work at a KFC fast food restaurant

    During the summer holiday of 2005,I thought I should do some meaningful instead of at home and watch ...