Combination Sum
update Jul 21, 2017 17:58
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.
Notice
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.
Example
Given candidate set [2,3,6,7] and target 7, a solution set is:
[7]
[2, 2, 3]Basic Idea:
整个程序肯定是Subsets的框架,但是又有一些细节需要注意。
题目说每个数字可以使用多次,隐含了重复元素其实是没有意义的,所以我们可以先去重。去重的方法类似于quick sort中的partition函数,2 pointers。
如何实现多次使用某个元素呢?只要在dfs传递参数时传递 i 而不是 i + 1 即可。
Python Code:
update Jan 9, 2017 15:35
Update: 新的思考(better solution)
首先我们分析一下之前这种方法的时间空间复杂度。之前的dfs算法中,一共会有 target / min(candidates) 层,每一层会有 len(candidates) 个分支,如果 input 的 target sum 非常大,会有很深的递归深度,同时也会有很高的时间复杂度(如果input: {1,5,10,25}, target=99, 则最大递归深度为 99 / 1 = 99 层,总时间复杂度 O(4^99));
接下来,我们换一种方法考虑(详见 DFS notes)。这次我们如下定义 DFS:
共有
len(candidates)层;每层考虑使用一个 candidate 不同的次数;
所以第 i 层有
remain sum / candidates[i]个分支;
如此,如果按照刚刚的 input,时间复杂度就变为了 O(99^4),显著降低。递归深度也从99变4,空间复杂度降低。
实现思路:
这种方法实现的时候和之前有了较大的不同,但是只要理解了 dfs 具体在每层做了什么就不难写了。因为我们对于每个数考虑不同次数选用它,在dfs中一定会有一个 for loop 来进行这件事情,同时因为candidates的长度固定,我们可以传入一个int[len(candidates)] times 来记录选取每个 candidates 的次数,框架为:
基础版本的写法,最终的结果就保存在了 int[] times 中,每个元素对应 candidates 相应元素的次数;
Java Code: (LintCode version)