How would you go about testing all possible combinations of additions from a given set N
of numbers so they add up to a given final number?
A brief exam
function solve(n){
let DP = [];
DP[0] = DP[1] = DP[2] = 1;
DP[3] = 2;
for (let i = 4; i <= n; i++) {
DP[i] = DP[i-1] + DP[i-3] + DP[i-4];
}
return DP[n]
}
console.log(solve(5))
This is a Dynamic Solution for JS to tell how many ways anyone can get the certain sum. This can be the right solution if you think about time and space complexity.
This can be used to print all the answers as well
public void recur(int[] a, int n, int sum, int[] ans, int ind) {
if (n < 0 && sum != 0)
return;
if (n < 0 && sum == 0) {
print(ans, ind);
return;
}
if (sum >= a[n]) {
ans[ind] = a[n];
recur(a, n - 1, sum - a[n], ans, ind + 1);
}
recur(a, n - 1, sum, ans, ind);
}
public void print(int[] a, int n) {
for (int i = 0; i < n; i++)
System.out.print(a[i] + " ");
System.out.println();
}
Time Complexity is exponential. Order of 2^n
import java.util.*;
public class Main{
int recursionDepth = 0;
private int[][] memo;
public static void main(String []args){
int[] nums = new int[] {5,2,4,3,1};
int N = nums.length;
Main main = new Main();
main.memo = new int[N+1][N+1];
main._findCombo(0, N-1,nums, 8, 0, new LinkedList() );
System.out.println(main.recursionDepth);
}
private void _findCombo(
int from,
int to,
int[] nums,
int targetSum,
int currentSum,
LinkedList<Integer> list){
if(memo[from][to] != 0) {
currentSum = currentSum + memo[from][to];
}
if(currentSum > targetSum) {
return;
}
if(currentSum == targetSum) {
System.out.println("Found - " +list);
return;
}
recursionDepth++;
for(int i= from ; i <= to; i++){
list.add(nums[i]);
memo[from][i] = currentSum + nums[i];
_findCombo(i+1, to,nums, targetSum, memo[from][i], list);
list.removeLast();
}
}
}
A Javascript version:
function subsetSum(numbers, target, partial) {
var s, n, remaining;
partial = partial || [];
// sum partial
s = partial.reduce(function (a, b) {
return a + b;
}, 0);
// check if the partial sum is equals to target
if (s === target) {
console.log("%s=%s", partial.join("+"), target)
}
if (s >= target) {
return; // if we reach the number why bother to continue
}
for (var i = 0; i < numbers.length; i++) {
n = numbers[i];
remaining = numbers.slice(i + 1);
subsetSum(remaining, target, partial.concat([n]));
}
}
subsetSum([3,9,8,4,5,7,10],15);
// output:
// 3+8+4=15
// 3+5+7=15
// 8+7=15
// 5+10=15
Here is a better version with better output formatting and C++ 11 features:
void subset_sum_rec(std::vector<int> & nums, const int & target, std::vector<int> & partialNums)
{
int currentSum = std::accumulate(partialNums.begin(), partialNums.end(), 0);
if (currentSum > target)
return;
if (currentSum == target)
{
std::cout << "sum([";
for (auto it = partialNums.begin(); it != std::prev(partialNums.end()); ++it)
cout << *it << ",";
cout << *std::prev(partialNums.end());
std::cout << "])=" << target << std::endl;
}
for (auto it = nums.begin(); it != nums.end(); ++it)
{
std::vector<int> remaining;
for (auto it2 = std::next(it); it2 != nums.end(); ++it2)
remaining.push_back(*it2);
std::vector<int> partial = partialNums;
partial.push_back(*it);
subset_sum_rec(remaining, target, partial);
}
}
This is similar to a coin change problem
public class CoinCount
{
public static void main(String[] args)
{
int[] coins={1,4,6,2,3,5};
int count=0;
for (int i=0;i<coins.length;i++)
{
count=count+Count(9,coins,i,0);
}
System.out.println(count);
}
public static int Count(int Sum,int[] coins,int index,int curSum)
{
int count=0;
if (index>=coins.length)
return 0;
int sumNow=curSum+coins[index];
if (sumNow>Sum)
return 0;
if (sumNow==Sum)
return 1;
for (int i= index+1;i<coins.length;i++)
count+=Count(Sum,coins,i,sumNow);
return count;
}
}