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:
For example, given candidate set 2,3,6,7
and target 7
,
A solution set is:
[7]
[2, 2, 3]
This is a mutation of subset sum problem. It has pseudo polynomial solution, which can be done in DP.
The problem can also be asked like: give sum n, and m different valued coins, how many ways can you make changes from these coins, order doesn't matter.
The easier version is to just output how many ways . just a few lines. the idea is the knapsack solution. time complexity O(n*target),space complexity O(target)
public void combinationSum(int[] candidates, int target) { // Start typing your Java solution below // DO NOT write main() function int dp[]=new int[target+1]; dp[0]=1; for(int i=0;i<candidates.length;i++) for(int s=0;s<target+1;s++){ if(s>=candidates[i]) dp[s]=dp[s-candidates[i]]+dp[s]; } System.out.println(dp[target]); return; }
The harder version is to output the subset candidates. still the same idea, just a few modifications. time complexity stays but space complexity increases.
import java.util.*; public class Solution { public ArrayList<ArrayList<Integer>> combinationSum(int[] candidates, int target) { // Start typing your Java solution below // DO NOT write main() function Hashtable h=new Hashtable<Integer,ArrayList<ArrayList<Integer>>>(); Arrays.sort(candidates); //not necessary, just to get the results in format ArrayList<Integer> m=new ArrayList<Integer>(); ArrayList<ArrayList<Integer>> n=new ArrayList<ArrayList<Integer>>(); n.add(m); h.put(0,n); ArrayList<ArrayList<Integer>> a,b,c; for(int i=0;i<candidates.length;i++) for(int s=1;s<target+1;s++){ if(s>=candidates[i]&&h.containsKey(s-candidates[i])){ a=new ArrayList<ArrayList<Integer>>(); c=((ArrayList<ArrayList<Integer>>)(h.get(s-candidates[i]))); for(ArrayList<Integer> x:c){ ArrayList<Integer> y=new ArrayList<Integer>(x); y.add(candidates[i]); a.add(y);}//ugly just due to we can't modify collection while traversing if(h.containsKey(s)){ b=((ArrayList<ArrayList<Integer>>)(h.get(s))); b.addAll(a);} else h.put(s,a);} } return (ArrayList<ArrayList<Integer>>)h.get(target)==null?new ArrayList<ArrayList<Integer>>():(ArrayList<ArrayList<Integer>>)h.get(target);//still just for format }}
surely the harder version can be done by DFS or backtracking, which is easier for printing the result.
Let's do it using backtracking.
public class Solution { public ArrayList<ArrayList<Integer>> combinationSum(int[] a, int target) { // Start typing your Java solution below // DO NOT write main() function ArrayList<ArrayList<Integer>> res=new ArrayList<ArrayList<Integer>>(); ArrayList<Integer> l=new ArrayList<Integer>(); Arrays.sort(a); solve(a,target,0,0,l,res); return res; } public void solve(int[] a, int target, int sum, int i, ArrayList<Integer> l, ArrayList<ArrayList<Integer>> res){ if(sum==target){ res.add(l); return;} if(sum>target||i>=a.length) return; int n=0; while(n*a[i]+sum<=target){ solve(a,target,sum+n*a[i],i+1,l,res); ArrayList<Integer> tmp=new ArrayList<Integer>(l); l=tmp; l.add(a[i]); n++; } return; } }
if you are doing combinationSum2
public class Solution { public ArrayList<ArrayList<Integer>> combinationSum2(int[] a, int target) { // Start typing your Java solution below // DO NOT write main() function ArrayList<ArrayList<Integer>> res=new ArrayList<ArrayList<Integer>>(); ArrayList<Integer> l=new ArrayList<Integer>(); Arrays.sort(a); solve(a,target,0,0,l,res); return res; } public void solve(int[] a, int target, int sum, int i, ArrayList<Integer> l, ArrayList<ArrayList<Integer>> res){ if(sum==target){ res.add(l); return;} if(sum>target||i>=a.length) return; int n=0; int j=i; while(j<a.length&&a[j]==a[i]) j++;//diff while(n<=j-i){//diff solve(a,target,sum+n*a[i],j,l,res);//diff ArrayList<Integer> tmp=new ArrayList<Integer>(l); l=tmp; l.add(a[i]); n++; } return; } }