LeetCode 3082 - Find the Sum of the Power of All Subsequences
You are given an array nums and an integer k. For every subsequence of nums, we define its power as the number of subsequences inside it whose sum equals k. The task is to compute the total power across all subsequences of the original array.
Difficulty: 🔴 Hard
Topics: Array, Dynamic Programming
Solution
Problem Understanding
You are given an array nums and an integer k. For every subsequence of nums, we define its power as the number of subsequences inside it whose sum equals k.
The task is to compute the total power across all subsequences of the original array.
The wording is initially confusing because we are dealing with subsequences inside subsequences. A cleaner way to think about it is this:
- Pick any subsequence
Sofnums - Count how many subsequences of
Shave sum exactlyk - Add that count to the global answer
- Repeat for every possible subsequence
S
The final result is the sum of all these counts.
The constraints are important:
n <= 100k <= 100nums[i]can be large, but only sums up tokmatter
Since n = 100, enumerating all subsequences directly is impossible because there are 2^100 of them.
The small value of k strongly suggests a dynamic programming solution based on subset sums.
An important observation is that we are not simply counting subsequences with sum k. We are summing contributions across all outer subsequences.
For example, if a subsequence T has sum k, then every outer subsequence containing T contributes one count for T.
Suppose T uses m elements. The remaining n - m elements may either be included or excluded independently in the outer subsequence. Therefore:
- Each valid subsequence
Tcontributes2^(n - m)to the final answer
This transforms the problem into:
For every subsequence with sum
k, add2^(n - length).
That is the key simplification.
Important edge cases include:
- No subsequence sums to
k - Multiple identical values create many distinct subsequences
kmay be smaller than every element- Large element values greater than
kshould effectively be ignored in transitions - Arrays with many zeros are not possible because
nums[i] >= 1
Approaches
Brute Force
A brute force solution would generate every subsequence of nums.
For each subsequence S, we would again enumerate all subsequences of S and count how many have sum k.
This is correct because it follows the problem definition directly.
However, the complexity is catastrophic.
There are 2^n subsequences of the original array. For each one, there can again be up to 2^n inner subsequences. The total complexity becomes approximately O(4^n).
With n = 100, this is completely infeasible.
Key Insight
Instead of thinking about outer subsequences first, reverse the perspective.
Consider a subsequence T whose sum equals k.
How many outer subsequences contain T?
If T uses m positions, then each of the remaining n - m positions can independently be included or excluded.
Therefore, T appears inside exactly:
$$2^{n-m}$$
outer subsequences.
So the answer becomes:
$$\sum_{\text{subsequence } T,\ \sum(T)=k} 2^{n-|T|}$$
Now the problem is much easier.
We only need to count subsequences with sum k, weighted by 2^{-length} relative to 2^n.
This naturally leads to dynamic programming.
Approach Comparison
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(4^n) | O(n) | Enumerates all subsequences twice |
| Optimal DP | O(nk) | O(k) | Dynamic programming over subset sums |
Algorithm Walkthrough
Optimal Dynamic Programming
We define:
dp[s]= weighted count of subsequences with sums
Initially:
dp[0] = 1
This represents the empty subsequence.
We process each number one by one.
When adding a number x, every existing subsequence has two choices:
- Skip
x - Take
x
If we take x, the subsequence length increases by 1.
Recall that each valid subsequence contributes:
$$2^{n-\text{length}}$$
Instead of applying the full factor at the end, we distribute the contribution gradually.
A very elegant recurrence emerges:
When processing a new number:
- Existing subsequences remain unchanged
- New subsequences formed by taking
xinherit half the weight
This leads to the transition:
$$newDp[s+x] += dp[s]$$
while every iteration doubles all existing contributions because every outer element can either appear or not appear.
A cleaner implementation uses:
$$dp[j] = 2 \cdot dp[j] + dp[j-x]$$
processed backwards.
Numbered Steps
- Create a DP array of size
k + 1. - Set
dp[0] = 1because the empty subsequence has sum0. - Process each number
xinnums. - Iterate sums backward from
kdown to0. - For every sum
j:
- Double
dp[j]because every existing subsequence may either include or exclude the current outer element. - If
j >= x, adddp[j - x]because subsequences summing toj - xcan extend withx.
- Apply modulo arithmetic after every update.
- After processing all elements, return
dp[k].
Why it works
The DP maintains the invariant:
$$dp[s]$$
equals the total contribution of all subsequences with sum s after processing some prefix of the array.
Every new element doubles all existing contributions because each outer subsequence may independently include or exclude the current element.
Additionally, choosing the current element creates new subsequences with larger sums.
Backward iteration prevents reusing the same element multiple times in a single iteration, exactly like standard subset-sum DP.
Thus, every valid subsequence with sum k contributes exactly the correct number of containing outer subsequences.
Python Solution
from typing import List
class Solution:
def sumOfPower(self, nums: List[int], k: int) -> int:
MOD = 10**9 + 7
dp = [0] * (k + 1)
dp[0] = 1
for num in nums:
new_dp = [0] * (k + 1)
for s in range(k + 1):
# Exclude current number from subsequence
new_dp[s] = (new_dp[s] + dp[s] * 2) % MOD
# Include current number
if s + num <= k:
new_dp[s + num] = (new_dp[s + num] + dp[s]) % MOD
dp = new_dp
return dp[k]
The implementation directly follows the mathematical interpretation of the problem.
The array dp[s] stores the total weighted contribution for subsequences whose sum equals s.
At every element:
- Existing contributions are doubled because the current element may or may not appear in the outer subsequence
- We also create new subsequences by including the current element in the inner subsequence
The separate new_dp array avoids accidentally reusing the same element multiple times during a single iteration.
Since only sums up to k matter, the DP size remains small.
All operations are performed modulo 10^9 + 7.
Go Solution
package main
func sumOfPower(nums []int, k int) int {
const MOD int = 1_000_000_007
dp := make([]int, k+1)
dp[0] = 1
for _, num := range nums {
newDp := make([]int, k+1)
for s := 0; s <= k; s++ {
// Exclude current number
newDp[s] = (newDp[s] + dp[s]*2) % MOD
// Include current number
if s+num <= k {
newDp[s+num] = (newDp[s+num] + dp[s]) % MOD
}
}
dp = newDp
}
return dp[k]
}
The Go implementation mirrors the Python logic closely.
A new DP slice is allocated for every iteration to avoid in-place update issues.
Go uses fixed-width integers, so modulo operations are applied immediately to prevent overflow growth.
Slices are naturally initialized to zero, so no explicit initialization is needed beyond setting dp[0] = 1.
Worked Examples
Example 1
Input:
nums = [1,2,3]
k = 3
Initial state:
| Sum | dp |
|---|---|
| 0 | 1 |
| 1 | 0 |
| 2 | 0 |
| 3 | 0 |
After processing 1
| Sum | Value |
|---|---|
| 0 | 2 |
| 1 | 1 |
| 2 | 0 |
| 3 | 0 |
Explanation:
- Existing empty subsequence doubles
- Including
1creates sum1
After processing 2
| Sum | Value |
|---|---|
| 0 | 4 |
| 1 | 2 |
| 2 | 2 |
| 3 | 1 |
Explanation:
- Existing values double
- Adding
2creates new sums
After processing 3
| Sum | Value |
|---|---|
| 0 | 8 |
| 1 | 4 |
| 2 | 4 |
| 3 | 6 |
Final answer:
6
Example 2
Input:
nums = [2,3,3]
k = 5
Initial:
| Sum | dp |
|---|---|
| 0 | 1 |
| 1 | 0 |
| 2 | 0 |
| 3 | 0 |
| 4 | 0 |
| 5 | 0 |
After processing 2
| Sum | Value |
|---|---|
| 0 | 2 |
| 2 | 1 |
After processing first 3
| Sum | Value |
|---|---|
| 0 | 4 |
| 2 | 2 |
| 3 | 2 |
| 5 | 1 |
After processing second 3
| Sum | Value |
|---|---|
| 0 | 8 |
| 2 | 4 |
| 3 | 6 |
| 5 | 4 |
Final answer:
4
Example 3
Input:
nums = [1,2,3]
k = 7
No subsequence can reach sum 7.
Therefore:
0
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(nk) | For each element, we iterate through all sums up to k |
| Space | O(k) | Only one DP array of size k + 1 is maintained |
The algorithm is efficient because k <= 100.
Even with n = 100, the total number of DP transitions is only about 10,000, which is easily manageable.
Test Cases
sol = Solution()
# Provided examples
assert sol.sumOfPower([1,2,3], 3) == 6 # Basic example
assert sol.sumOfPower([2,3,3], 5) == 4 # Duplicate values
assert sol.sumOfPower([1,2,3], 7) == 0 # Impossible target
# Single element equal to k
assert sol.sumOfPower([5], 5) == 1 # One valid subsequence
# Single element not equal to k
assert sol.sumOfPower([5], 3) == 0 # No valid subsequence
# Multiple identical values
assert sol.sumOfPower([1,1,1], 2) == 6 # Multiple combinations
# All elements larger than k
assert sol.sumOfPower([10,20,30], 5) == 0 # Cannot form target
# Larger combination counts
assert sol.sumOfPower([1,1,1,1], 2) == 24 # Many overlapping subsequences
# k equals total sum
assert sol.sumOfPower([1,2,3], 6) == 1 # Only full array works
# Minimum constraints
assert sol.sumOfPower([1], 1) == 1 # Smallest valid input
Test Summary
| Test | Why |
|---|---|
[1,2,3], k=3 |
Standard mixed example |
[2,3,3], k=5 |
Duplicate values |
[1,2,3], k=7 |
Impossible target |
[5], k=5 |
Single valid element |
[5], k=3 |
Single invalid element |
[1,1,1], k=2 |
Multiple equivalent subsequences |
[10,20,30], k=5 |
All values exceed target |
[1,1,1,1], k=2 |
Stress repeated combinations |
[1,2,3], k=6 |
Only one full-length subsequence |
[1], k=1 |
Minimum boundary input |
Edge Cases
No subsequence sums to k
This is one of the most important cases because many implementations accidentally produce nonzero values due to incorrect initialization or transition ordering.
For example:
nums = [1,2,3]
k = 10
No subset can reach 10, so the answer must remain 0.
The DP handles this naturally because unreachable sums are never updated.
Duplicate numbers
Arrays with repeated values can create many distinct subsequences that have the same numeric contents but use different indices.
For example:
nums = [1,1,1]
k = 2
There are three distinct subsequences producing sum 2.
The DP processes elements positionally, so each occurrence contributes independently and correctly counts all distinct subsequences.
Large values bigger than k
Values larger than k cannot participate in any valid inner subsequence.
For example:
nums = [1000, 2000]
k = 5
A naive implementation might waste time considering impossible transitions.
This solution checks:
if s + num <= k
so impossible sums are skipped immediately.
Full-array target
Sometimes only the entire array achieves the target.
Example:
nums = [1,2,3]
k = 6
Only one subsequence has sum 6.
Its contribution is:
$$2^{3-3} = 1$$
The DP correctly preserves this weighting automatically.