LeetCode #377 Medium

Combination Sum IV

Combination Sum IV: count the number of ordered sequences of numbers from nums that sum to target.

Constraints
  • 1 <= nums.length <= 200
  • 1 <= nums[i] <= 1000
  • All the elements of nums are unique.
  • 1 <= target <= 1000
dynamic-programmingarray
Open on LeetCode ↗
02

Intuition

Combination sum iv is misleadingly named. Despite the title, it counts permutations — [1, 2] and [2, 1] are counted as two different ways to reach 3. That single fact changes the entire solution, and reading the examples rather than the title is what reveals it. Because order matters, backtracking is unnecessary. Only the count is required, not the combinations themselves, so this becomes a counting DP: - dp[t] is the number of ordered ways to reach total t, and dp[t] = sum of dp[t − num] over every number that fits. The reasoning is direct: any sequence summing to t ends with some number num, and the part before it is a sequence summing to t − num. Adding up over all possible final numbers counts every sequence exactly once. The base case is dp[0] = 1 — there is exactly one way to reach zero, by choosing nothing. This seeds the entire table. The loop order is what distinguishes this from a combination count, and it is the whole lesson of the problem: Putting the target in the outer loop and the numbers in the inner counts permutations, because every number is considered as the final element at every total. Swapping them — numbers outside, target inside — counts combinations instead, which is the Coin Change II pattern. The two problems differ by nothing more than which loop is outermost. That is worth remembering, since the code looks nearly identical. The stated follow-up about negative numbers has no finite answer, since negatives allow infinitely long sequences.

How to spot this pattern

Despite the name, combination sum 4 leetcode counts permutations — [1,2] and [2,1] are separate answers. That's why the target loop is outer and the number loop is inner: iterating targets first lets every ordering be built independently.

03

Approach

Try it first

Before reading on: price up what the direct approach costs here, then ask what a single cell should mean, and which earlier cells it needs. Aim for O(target * len(nums)) time and O(target) space.

1

Read the examples, not the title

Despite its name, this problem counts permutations — [1, 2] and [2, 1] count separately. Recognising this from the examples determines everything that follows.

2

Count rather than enumerate

Only the number of ways is required, not the sequences themselves, so backtracking is unnecessary. A counting DP is both simpler and far faster.

3

Define the state

dp[t] is the number of ordered ways to reach total t. Every sequence ends with some number, which is what the transition below exploits.

4

Set the base case

dp[0] = 1 — exactly one way to reach zero, by choosing nothing. This single value seeds the whole table; setting it to 0 makes every result 0.

5

Apply the transition

dp[t] = sum of dp[t - num] over every number that fits. Each term counts the sequences ending in that number, so every sequence is counted exactly once.

6

Put the target in the outer loop

Target outside, numbers inside counts permutations. Swapping the loops counts combinations instead — the Coin Change II pattern. The code looks nearly identical, and this order is the only difference.

7

Cost of the tabulation

Each of the target states scans every number, giving O(target · n) time and O(target) space for the single array.

04

Solution & live demo

▶1class Solution:
▶2 def combinationSum4(self, nums:
▶3 list[int], target: int) -> int:
▶4 dp = [0] * (target + 1)
▶5 dp[0] = 1
▶6 for t in range(1, target + 1):
▶7 for num in nums:
▶8 if num <= t:
▶9 dp[t] += dp[t - num]
▶10 return dp[target]
05

Common pitfalls

Putting the number loop outside

✗ Wrong
for num in nums:
    for t in range(num, target + 1):
        dp[t] += dp[t - num]
✓ Right
for t in range(1, target + 1):
    for num in nums:

Number-outer counts each multiset once regardless of order — that's the combination count, which is a different and smaller answer. The loop order alone decides between combinations and permutations.

Not seeding dp[0]

✗ Wrong
dp = [0] * (target + 1)
✓ Right
dp[0] = 1

The empty sequence is the one way to reach a target of 0, and every count builds on it. Without the seed the entire table stays zero.

Ignoring overflow on the count

✗ Wrong
int[] dp = new int[target + 1];
✓ Right
// the problem guarantees the answer fits in a 32-bit int

Intermediate dp values can exceed a signed int even when the final answer fits — LeetCode's constraints permit this, and the accepted solutions rely on the wraparound cancelling out. Worth knowing you're leaning on that rather than assuming the arithmetic is clean.

06

Edge cases

target is smaller than every num

The inner sum never finds a fitting num for any positive t up to target, so dp[target] = 0.

nums contains a divisor of target that repeats to hit it, e.g. nums=[9], target=3

9 never fits into a target of 3, so the answer is correctly 0.

target = 0

dp[0] = 1 is the base case; if 0 is queried directly the answer is 1 (the empty sequence).

nums has a single 1

Exactly one sequence exists for any target: 1 repeated target times.

07

Complexity

Time
O(target * len(nums))
Space
O(target)
Target-outer, nums-inner loop order is what makes this count permutations rather than combinations.