Teaching Kids Programming – Combination Sum Up to Target (Unique Numbers) by Dynamic Programming Algorithms


Teaching Kids Programming: Videos on Data Structures and Algorithms

Given an array of distinct integers nums and a target integer target, return the number of possible combinations that add up to target. The answer is guaranteed to fit in a 32-bit integer.

Example 1:
Input: nums = [1,2,3], target = 4
Output: 7
Explanation:
The possible combination ways are:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)
Note that different sequences are counted as different combinations.

Example 2:
Input: nums = [9], target = 3
Output: 0

Constraints:
1 <= nums.length <= 200
1 <= nums[i] <= 1000
All the elements of nums are unique.
1 <= target <= 1000

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?

Thinking of this problem as: Given a knapsack with capacity T, and a list of items with their weights. Find out the number of possible combination that to pick the items into the knapsack i.e. sum of chosen items is T.

Bruteforce and BackTracking Algorithm to Pick the Numbers

For each item, we can choose pick (if it is less than the T or we have capacity to pack this) or pick next one. Once there is no remaining capacity in the knapsack, we increment the answer.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution:
    def combinationSumToTarget(self, nums: List[int], target: int) -> int:
        ans = 0
        
        def pick(left, T):
            nonlocal ans
            if T == 0:
                ans += 1
                return
            for i in range(len(nums)):
                if T >= nums[i]:
                    pick(i, T - nums[i])
                
        pick(0, target)
        return ans
class Solution:
    def combinationSumToTarget(self, nums: List[int], target: int) -> int:
        ans = 0
        
        def pick(left, T):
            nonlocal ans
            if T == 0:
                ans += 1
                return
            for i in range(len(nums)):
                if T >= nums[i]:
                    pick(i, T - nums[i])
                
        pick(0, target)
        return ans

One optimisation is to sort the items in the ascending order – and backtrack once the item is exceeding the current capacity. However, this is still too slow – as there are exponential combinations of choosing the items.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution:
    def combinationSumToTarget(self, nums: List[int], target: int) -> int:
        ans = 0
        
        nums.sort()
        def pick(left, T):
            nonlocal ans
            if T == 0:
                ans += 1
                return
            for i in range(len(nums)):
                if T >= nums[i]:
                    pick(i, T - nums[i])
                else:
                    break
                
        pick(0, target)
        return ans
class Solution:
    def combinationSumToTarget(self, nums: List[int], target: int) -> int:
        ans = 0
        
        nums.sort()
        def pick(left, T):
            nonlocal ans
            if T == 0:
                ans += 1
                return
            for i in range(len(nums)):
                if T >= nums[i]:
                    pick(i, T - nums[i])
                else:
                    break
                
        pick(0, target)
        return ans

Bottom Up Dynamic Programming Algorithm of Solving Knapsack Problem

Let tex_55dc2fb486151edbaa73e6045195d561 Teaching Kids Programming - Combination Sum Up to Target (Unique Numbers) by Dynamic Programming Algorithms algorithms Dynamic Programming dynamic programming Knapsack Problems math python teaching kids programming youtube video be the number of ways to pick items to capacity T, then it is sum of tex_2c64828e424c0a737785cf795fcd5a59 Teaching Kids Programming - Combination Sum Up to Target (Unique Numbers) by Dynamic Programming Algorithms algorithms Dynamic Programming dynamic programming Knapsack Problems math python teaching kids programming youtube video where i is the items. This is actually similar to climbing stairs problem.

With Bottom-up DP, we calculate the f(0), f(1), f(2) and up to f(T). and we store the numbers in an O(T) array so that we can re-use the values without needing to calculate them.

1
2
3
4
5
6
7
8
9
10
class Solution:
    def combinationSumToTarget(self, nums: List[int], target: int) -> int:
        n = len(nums)
        dp = [0] * (target + 1)
        dp[0] = 1
        for i in range(1, target + 1):
            for j in nums:
                if i >= j:
                    dp[i] += dp[i - j]
        return dp[-1]
class Solution:
    def combinationSumToTarget(self, nums: List[int], target: int) -> int:
        n = len(nums)
        dp = [0] * (target + 1)
        dp[0] = 1
        for i in range(1, target + 1):
            for j in nums:
                if i >= j:
                    dp[i] += dp[i - j]
        return dp[-1]

The time complexity is O(T.N) where N is the number of the items. And space complexity is O(T) as we need an array with size T – to calculate the value F(0), F(1) .. to F(T).

Top Down Dynamic Programming Algorithm to Compute the Combination Sum of Target

As soon as we have the Dynamic Programming Transistion Function and the terminal conditions, we can implement DP in a straightforward Recursive manner. However, we need to use the @cache or @lru_cache(None) to apply the memoization technique so that only the F(0) to F(T) values are calculated once.

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution:
    def combinationSumToTarget(self, nums: List[int], target: int) -> int:
        @cache
        def f(n):
            if n == 0:
                return 1
            if n < 0:
                return 0
            ans = 0
            for i in nums:
                ans += f(n - i)
            return ans
        return f(target)
class Solution:
    def combinationSumToTarget(self, nums: List[int], target: int) -> int:
        @cache
        def f(n):
            if n == 0:
                return 1
            if n < 0:
                return 0
            ans = 0
            for i in nums:
                ans += f(n - i)
            return ans
        return f(target)

Time complexity is O(NT) and space complexity is O(T) – same as the Bottom-up Dynamic Programming Algorithm.

See also: Using BackTracking Algorithm to Find the Combination Integer Sum

Another similar problem of unbounded knapsack problem via Dynamic Programming Algorithms: Teaching Kids Programming – Dynamic Programming Algorithm to Compute Minimum Number of Coins

Knapsack Problems

–EOF (The Ultimate Computing & Technology Blog) —

GD Star Rating
loading...
959 words
Last Post: Java's Algorithm of Checking if Error is of Type (Error Inheritance Tree)
Next Post: Ways to Prevent an Account Takeover Fraud

The Permanent URL is: Teaching Kids Programming – Combination Sum Up to Target (Unique Numbers) by Dynamic Programming Algorithms

Leave a Reply