这道题是LeetCode里的第40道题。

题目要求:

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

candidates 中的每个数字在每个组合中只能使用一次。

说明:

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

示例 1:

输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]

示例 2:

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

解法和第39题几乎一样,区别在于本题每一个数字只能使用一次,但数字在数组中是可以重复的。同样,还是使用回溯剪枝法,先对 candidates 数组元素排序。排序后进行循环递归。具体代码如下:

提交代码:

class Solution {
public:
vector<vector<int>> res;
vector<int> ans;
void getres(vector<int>& candidates,int target,int k,vector<int> ans){
int size=candidates.size();
for(int i=k;i<size;i++){
if(target-candidates[i]>0){
if(i>k&&candidates[i]==candidates[i-1])continue;
ans.push_back(candidates[i]);
getres(candidates,target-candidates[i],i+1,ans);
ans.pop_back();
}
else if(target-candidates[i]<0){return;}
else{
ans.push_back(candidates[i]);
res.push_back(ans);
ans.pop_back();
return;
}
}
return;
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(),candidates.end());
getres(candidates,target,0,ans);
return res;
}
};

代码和第39题几乎一样,只改了两个地方,第一个是第11行,参数由 i 改为 i+1,这是能想到的确保每一个数字只使用一次的改法。但是这样改还并不完全,因为最终答案会有重复的解答。第二个改法纠结我好久:最笨的想法是先把解保存在一个 set 集合中,然后在转入 vector<vector<int>> 中,但这样太慢了,不想用。那么是什么原因造成解的重复呢?原因就是 candidates 数组中包含着重复数,例如:

示例1:candidates = [10,1,2,7,6,1,5],target = 8,标准解答:[[1,2,5],[1,7],[1,1,6],[2,6]]

没有第九行代码前的解答:[[1,1,6],[1,2,5],[1,7],[1,2,5],[1,7],[2,6]],其中第二个和第四个重复,第三个和第五个重复。因为数组中有两个1,这两个1分别组合了一次,造成了重复。知道原因了,就好解决,首先想到的是加入条件candidates[i]==candidates[i-1]当前后元素相等时,直接跳过本次循环,但问题又来了:[1,1,6]这个解,前后元素相等,但不重复,怎么办?这个我想了好久,最后看评论:因为当前层,如果再取下一个一样的数的话,就会造成重复,但是在下一层加入就不会,因为当前层是替换,如果拿一个一样的替换肯定会重复。再加入条件:i>k 就能保证既不会缺少[1,1,6]这个解,也保证了解的互异。所以第九行加入代码:if(i>k&&candidates[i]==candidates[i-1])continue;,然后剩下的剪枝第39题都有。

提交结果:

个人总结:

本题和第39题不同,难度也体现在最后答案的重复上。回溯法的本质还是递归,递归最难的地方就是容易弄混循环和递归层数,需要画图仔细分析,递归循环是个树图,画图也好容易分析。最后这题也可以不用排序,因为数字只使用一次,但是结果是会有重复的,而且重复的是无规则的,效率低。

最新文章

  1. SpringMVC对异常进行全局处理,并区分对待ajax和普通请求
  2. JVM内存格局总结
  3. 2016年12月22日 星期四 --出埃及记 Exodus 21:17
  4. 带缓存的输入输出-bufferedinputstream类与bufferedoutputstream类
  5. wordpress学习二:源码目录结构和启动流程
  6. 使用Visual Studio创建简单的自己定义Web Part 部件属性
  7. php防止ddos,dns,集群攻击的实现代码
  8. ActiveMQ学习笔记(二) JMS与Spring
  9. Qt调用外部程序QProcess通信
  10. C#彻底解决Web Browser 跨域读取Iframes内容
  11. lua的string库
  12. perl的package和module
  13. LeetCode(65)-Power of Four
  14. 关于map的初级应用
  15. fiddler限制网速
  16. x264阅读记录-3
  17. Windows Server 2016 启用完整版任务管理器
  18. Oracle EBS OPM 子库存转移
  19. 动画的使用—Drawable Animation
  20. LOJ#6544. 杀苍蝇(计算几何)

热门文章

  1. 小程序 显示Toobar
  2. hihocoder1032 最长回文子串
  3. SQL2005中使用backup、restore来备份和恢复数据库
  4. 关于 java swing 使用按钮关闭窗口
  5. 补题—Codeforces Round #346 (Div. 2) _智商欠费系列
  6. poj2312Battle City BFS
  7. WPF知识点全攻略09- 附加属性
  8. 阿里Java架构师面试高频300题:集合+JVM+Redis+并发+算法+框架等
  9. 快学UiAutomator创建第一个实例
  10. CPP-基础:C++拷贝构造函数详解