Problem:
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.
Note:
- 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.
For example, given candidate set 2,3,6,7
and target 7
,
A solution set is:
[7]
[2, 2, 3]
不难看出,这道题用递归求解比较简单。首先,candidates数组可能是无序的,为了使结果按升序排列,需要先对candidates数组进行排序。从最大(或最小)的candidate开始,对于target=k*candidate+remain。如果remain=0,则在返回结果中添加包含k个candidate的解,如果remain>0,则先求解combinationSum(candidates,remain),注意只能在小于(大于)candidate的元素中搜索解,如果结果不为空,则在每一个解中添加k个candidate。最后合并所有可行的k下的解并返回。
Solution:
public class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
if(candidates==null||candidates.length==0)
return new ArrayList<>();
Arrays.sort(candidates);
return subCombination(candidates,candidates.length-1,target);
}
private List<List<Integer>> subCombination(int[] candidates,int p, int target) {
if(target<candidates[0])
return new ArrayList<>();
int l = 0,r = p,m;
while(l<r-1)
{
m = (l+r)/2;
if(candidates[m]>target)
r = m;
else
l = m;
}
if(candidates[r]<=target)
l = r;
List<List<Integer>> res = new ArrayList<>();
for(int i=0;i<=target/candidates[l];i++)
{
int remain = target-i*candidates[l];
if(remain==0)
{
List<Integer> arr = new ArrayList<>();
for(int j=0;j<i;j++)
arr.add(candidates[l]);
res.add(arr);
}
else
{
if(l>0)
{
List<List<Integer>> tmp = new ArrayList<>();
tmp = subCombination(candidates,l-1, remain);
if(tmp.size()>0)
{
for(List<Integer> list:tmp)
{
for(int j=0;j<i;j++)
list.add(candidates[l]);
}
res.addAll(tmp);
}
}
}
}
return res;
}
}
public List<List<Integer>> combinationSum(int[] candidates, int target) {
if(candidates==null||candidates.length==0)
return new ArrayList<>();
Arrays.sort(candidates);
return subCombination(candidates,candidates.length-1,target);
}
private List<List<Integer>> subCombination(int[] candidates,int p, int target) {
if(target<candidates[0])
return new ArrayList<>();
int l = 0,r = p,m;
while(l<r-1)
{
m = (l+r)/2;
if(candidates[m]>target)
r = m;
else
l = m;
}
if(candidates[r]<=target)
l = r;
List<List<Integer>> res = new ArrayList<>();
for(int i=0;i<=target/candidates[l];i++)
{
int remain = target-i*candidates[l];
if(remain==0)
{
List<Integer> arr = new ArrayList<>();
for(int j=0;j<i;j++)
arr.add(candidates[l]);
res.add(arr);
}
else
{
if(l>0)
{
List<List<Integer>> tmp = new ArrayList<>();
tmp = subCombination(candidates,l-1, remain);
if(tmp.size()>0)
{
for(List<Integer> list:tmp)
{
for(int j=0;j<i;j++)
list.add(candidates[l]);
}
res.addAll(tmp);
}
}
}
}
return res;
}
}