题目描述:

给定一个无重复元素的数组 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. 线程并发线程安全介绍及java.util.concurrent包下类介绍

    线程Thread,在Java开发中多线程是必不可少的,但是真正能用好的并不多! 首先开启一个线程三种方式 ①new Thread(Runnable).start() ②thread.start(); ...

  2. Jdeveloper下Svn的使用

    Jdeveloper下Svn的使用 官方pdf:jdeveloper使用svn 官方网地址:http://www.oracle.com/technetwork/cn/java/subversion-0 ...

  3. 读写大“二进制”文件,不必申请很大内存(fopen,fread,fwrite,fclose)

    <?php /** * 读写大二进制文件,不必申请很大内存 * 只有读取到内容才创建文件 * 保证目录可写 * * @param string $srcPath 源文件路径 * @param s ...

  4. 记录GOPATH在GOLAND中的坑

    首先我的环境已配置好: GO的目录结构是: add.go package calc//函数名必须大写首字母,不然外部包找不到 func Add(a int,b int)(int){ return a+ ...

  5. dedecms导出csv文件

    1.mshd_orderlist.tpl <form id="frm" method="GET" action="mshd_orderlist. ...

  6. 快速完成网页设计,10个顶尖响应式HTML5网页模板助你一臂之力

    为了寻找一个优质的网页模板,网页设计师和开发者往往可能会花上大半天的时间.不过幸运的是,现在的网页设计师和开发人员已经开始共享HTML5,Bootstrap和CSS3中的免费网页模板资源.鉴于网站模板 ...

  7. WCF技术剖析(卷1)WCF全面解析文摘

    第1章 wcf简介 soa体现的是一种对关注点进行分解的思想,与技术无关 soa的基本思想: a.服务自治  独立部署,不依赖其他 b.依赖于开放的标准  采用xml,xsd,及wsdl作为服务描述的 ...

  8. 递归,回溯和DFS的区别

    递归是一种算法结构,回溯是一种算法思想一个递归就是在函数中调用函数本身来解决问题回溯就是通过不同的尝试来生成问题的解,有点类似于穷举,但是和穷举不同的是回溯会“剪枝”,意思就是对已经知道错误的结果没必 ...

  9. String 、 StringBuffer 和 StringBuilder

    StringBuffer (一个线程安全的可变字符串序列,用于多线程) A thread-safe, mutable sequence of characters. StringBuilder (可变 ...

  10. DW2.0

    一.DW2.0从企业的角度,吸引企业的原因: 1.数据仓库基础设施的成本不再持续增长.在第一代数据仓库中,技术基础设施的成本是不断增长的,随着数据量的增长,基础设施的成本会以指数级增长.但是使用DW2 ...