package com.freetymekiyan.algorithms.level.medium;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import java.util.Arrays;

/**
 * Given an integer array with all positive numbers and no duplicates, find the number of possible combinations that add
 * up to a positive integer target.
 * <p>
 * Example:
 * <p>
 * nums = [1, 2, 3]
 * target = 4
 * <p>
 * The possible combination ways are:
 * (1, 1, 1, 1)
 * (1, 1, 2)
 * (1, 2, 1)
 * (1, 3)
 * (2, 1, 1)
 * (2, 2)
 * (3, 1)
 * <p>
 * Note that different sequences are counted as different combinations.
 * <p>
 * Therefore the output is 7.
 * Follow up:
 * What if negative numbers are allowed in the given array?
 * How does it change the problem?
 * What limitation we need to add to the question to allow negative numbers?
 * <p>
 * Tags: Dynamic Programming
 * Similar Problems: (M) Combination Sum
 */
public class CombinationSum4 {

    private CombinationSum4 c;

private int[] dp;

/**
 *
 * @param nums
 * @param target
 * @return
 */
public int combinationSum4(int[] nums, int target) {
    dp = new int[target + 1];
    Arrays.fill(dp, -1);
    dp[0] = 1;
    return helper(nums, target);
}

private int helper(int[] nums, int target) {
    if (target == 0) {
        return 1;
    }
    if (dp[target] != -1) {
        return dp[target];
    }
    int res = 0;
    for (int i = 0; i < nums.length; i++) {
        if (target >= nums[i]) {
            res += helper(nums, target - nums[i]);
        }
    }
    dp[target] = res;
    return res;
}

    @Before
    public void setUp() {
        c = new CombinationSum4();
    }

    @Test
    public void testExamples() {
        int[] nums = {1, 2, 3};
        int target = 4;
        Assert.assertEquals(7, c.combinationSum4(nums, target));
        target = 6;
        Assert.assertEquals(24, c.combinationSum4(nums, target));
    }

    @After
    public void tearDown() {
        c = null;
    }

}

@@ -967,16 +967,20 @@
 um4 c;%0A%0A
+    
 private 
@@ -994,62 +994,12 @@
 p;%0A%0A
-/**%0A *%0A * @param nums%0A * @param target%0A * @return%0A */%0A
+    
 publ
@@ -1043,24 +1043,28 @@
 t target) %7B%0A
+    
     dp = new
@@ -1085,16 +1085,20 @@
 1%5D;%0A    
+ 
+   
 Arrays.f
@@ -1110,16 +1110,20 @@
 p, -1);%0A
+    
     dp%5B0
@@ -1129,24 +1129,28 @@
 0%5D = 1;%0A    
+ 
+   
 return helpe
@@ -1166,19 +1166,27 @@
 arget);%0A
-%7D%0A%0A
+    %7D%0A%0A    
 private 
@@ -1218,24 +1218,28 @@
 t target) %7B%0A
+    
     if (targ
@@ -1253,24 +1253,28 @@
 ) %7B%0A        
+  
+  
 return 1;%0A  
@@ -1275,22 +1275,30 @@
  1;%0A    
-%7D%0A
+    %7D%0A   
     
+ 
 if (dp%5Bt
@@ -1317,24 +1317,28 @@
 ) %7B%0A        
+    
 return dp%5Bta
@@ -1344,26 +1344,34 @@
 arget%5D;%0A    
+   
+ 
 %7D%0A
+    
     int res 
@@ -1375,16 +1375,20 @@
 es = 0;%0A
+    
     for 
@@ -1423,32 +1423,36 @@
  i++) %7B%0A        
+    
 if (target %3E= nu
@@ -1456,24 +1456,28 @@
  nums%5Bi%5D) %7B%0A
+    
             
@@ -1527,16 +1527,28 @@
     
-%7D%0A
+    %7D%0A    
     %7D%0A
+    
     
@@ -1565,16 +1565,20 @@
  = res;%0A
+    
     retu
@@ -1585,16 +1585,416 @@
 rn res;%0A
+    %7D%0A%0A    public int combinationSum4BottomUp(int%5B%5D nums, int target) %7B%0A        int%5B%5D comb = new int%5Btarget + 1%5D;%0A        comb%5B0%5D = 1;%0A        for (int i = 1; i %3C comb.length; i++) %7B%0A            for (int j = 0; j %3C nums.length; j++) %7B%0A                if (i - nums%5Bj%5D %3E= 0) %7B%0A                    comb%5Bi%5D += comb%5Bi - nums%5Bj%5D%5D;%0A                %7D%0A            %7D%0A        %7D%0A        return comb%5Btarget%5D;%0A    
 %7D%0A%0A    @

update Combination Sum 4 with bottom-up approach