leetcode -- Combination Sum -- 重点
2015-12-14 12:52
267 查看
https://leetcode.com/problems/combination-sum/
参考回溯的模板,跟dfs binary tree 模板不一样/article/1607287.html
例如:参考/article/4879769.html
比如对于数组3,2,6,7,target = 7,对数组排序得到[2,3,6,7]
1、第1个数字选取2, 那么接下来就是解决从数组[2,3,6,7]选择数字且target = 7-2 = 5
2、第2个数字选择2,那么接下来就是解决从数组[2,3,6,7]选择数字且target = 5-2 = 3
3、第3个数字选择2,那么接下来就是解决从数组[2,3,6,7]选择数字且target = 3-2 = 1
4、此时target = 1小于数组中的所有数字,失败,回溯,重新选择第3个数字
5、第3个数字选择3,那么接下来就是解决从数组[2,3,6,7]选择数字且target = 3-3 = 0
6、target = 0,找到了一组解,继续回溯寻找其他解
/article/2219400.html给出了比较详细的思路
这种方法好理解,但是效率低,可以改进。ref里面提到了改进方法,要先sort数组,why?现在还没太理解
参考回溯模板:
以下是程序
这里需要注意的就是 knum其实就是stack的作用,这里 knums + [candidates[i]]相当于复制了一分新的搜索路径,所以不需要像模板一样,修改了全局变量,再恢复全局变量
此外,在存储最后结果的时候
最好是复制res,即
这个code效率很低
为了简便,还可以去掉stack,直接改成
思路1 回溯
这里参照dfs tree2 组合树的建树方法,因为有重合数字,所以子节点不再是只是A[k]后面的元素,子节点应该还是原来所有的元素。参考回溯的模板,跟dfs binary tree 模板不一样/article/1607287.html
例如:参考/article/4879769.html
比如对于数组3,2,6,7,target = 7,对数组排序得到[2,3,6,7]
1、第1个数字选取2, 那么接下来就是解决从数组[2,3,6,7]选择数字且target = 7-2 = 5
2、第2个数字选择2,那么接下来就是解决从数组[2,3,6,7]选择数字且target = 5-2 = 3
3、第3个数字选择2,那么接下来就是解决从数组[2,3,6,7]选择数字且target = 3-2 = 1
4、此时target = 1小于数组中的所有数字,失败,回溯,重新选择第3个数字
5、第3个数字选择3,那么接下来就是解决从数组[2,3,6,7]选择数字且target = 3-3 = 0
6、target = 0,找到了一组解,继续回溯寻找其他解
/article/2219400.html给出了比较详细的思路
这种方法好理解,但是效率低,可以改进。ref里面提到了改进方法,要先sort数组,why?现在还没太理解
class Solution(object): def dfs(self, candidates, target, knums, solutions): sum_knums = sum(knums) if sum_knums == target : return knums for i in candidates: all_sum = sum_knums + i if all_sum <= target: res = self.dfs(candidates, target, knums + [i], solutions) if res: res.sort() if res not in solutions: solutions.append(res) def combinationSum(self, candidates, target): res = [] self.dfs(candidates, target, [], res) return res
思路2 回溯改进,去重复
因为思路1中的结果可能有重复,所以为了消除重复结果,可以按照/article/2219400.html 说的先排序,然后只搜索比当前搜索节点大的子节点。为什么要排序呢?其实没必要排序,对于当前节点A[i], 只需要搜索A[j], j>i即可,照样可以消除重复结果,跟求组合数或者子集的思路一样。只不过 一开始sort之后,最后回溯的结果就不需要再sort一下再存入solution了。所以最好还是一开始就排序。此外,还可以方便剪枝, 因为如果加上当前子节点之后的sum以及超过了target,那么就不用再继续搜索后续节点了,因为任意后续节点都更使得sum更大。这里暂时不考虑排序参考回溯模板:
void dfs(int 当前状态) { if(当前状态为边界状态) { 记录或输出 return; } for(i=0;i<n;i++) //横向遍历解答树所有子节点 { //扩展出一个子状态。 修改了全局变量//例如存储路径的stack。这里其实可以放到dfs之前 if(子状态满足约束条件)//求出current candidates { dfs(子状态) } 恢复全局变量//回溯部分例如存储路径的stack } }
以下是程序
class Solution(object): def dfs(self, candidates, start, end, target, knums, solutions): sum_knums = sum(knums) if sum_knums == target : return knums i = start #print 'start = %d' %start while i < end: all_sum = sum_knums + candidates[i] #print (i, all_sum) if all_sum <= target: res = self.dfs(candidates, i, end, target, knums + [candidates[i]], solutions) if res: res.sort() #if res not in solutions: solutions.append(res) i += 1 def combinationSum(self, candidates, target): res = [] #candidates.sort()#这里不需要排序 self.dfs(candidates, 0, len(candidates), target, [], res) return res
这里需要注意的就是 knum其实就是stack的作用,这里 knums + [candidates[i]]相当于复制了一分新的搜索路径,所以不需要像模板一样,修改了全局变量,再恢复全局变量
res = self.dfs(candidates, i, end, target, knums + [candidates[i]], solutions)
此外,在存储最后结果的时候
solutions.append(res)
最好是复制res,即
solutions.append(res[:])
思路3 标准 回溯,原数组排序
首先排序输入数组,因为这样每个可能的解knums都是排好序的,否则每次当sum_knums == target的时候,还要对knums进行sort之后才能放到solution里面。另外排序还有利于剪枝,提高效率这个code效率很低
class Solution(object): def dfs(self, candidates, start, end, target, knums, solutions): if sum(knums) == target: solutions.append(knums[:]) return else: i = start while i < end: knums.append(candidates[i]) if sum(knums) <= target: self.dfs(candidates, i, end, target, knums, solutions) else:#这里就是排序之后的剪枝,不需要继续搜后续节点 knums.pop() return knums.pop() i += 1 def combinationSum(self, candidates, target): res = [] self.dfs(sorted(candidates), 0, len(candidates), target, [], res) return res
为了简便,还可以去掉stack,直接改成
def dfs(self, candidates, start, end, target, knums, solutions): if sum(knums) == target: solutions.append(knums[:]) return else: i = start while i < end: if sum(knums) + candidates[i] <= target: self.dfs(candidates, i, end, target, knums + [candidates[i]], solutions) else:#这里就是排序之后的剪枝,不需要继续搜后续节点 return i += 1
相关文章推荐
- java读书笔记-java提高篇(2)
- node.js中的匿名函数, 回调函数和嵌套函数
- 对于图片的分析以及C#代码对图片进行灰化与反转
- 天平问题 三进制
- 用js动态生成css样式表
- android加混淆 方式与坑
- PHP访问.NET WebService的若干问题
- 转载收藏
- spring框架(一)
- linux limits.conf 配置
- linux limits.conf 配置
- 如何有效的积累你的测试知识?
- java获取当前时间后,经SimpleDateFormat格式化成String类型,差8小时
- IO协议栈前沿技术研究动态(2015存储峰会分享)
- 为什么移动Web应用程序很慢(译)
- 设计模式-单例模式
- SMO启发式选择
- 安裝 CentOS 7 後必做的七件事
- OC NSNumber和NSValue和NSDate和NSData
- angularjs实际工程目录结构