3247. Number of Subsequences with Odd Sum 🔒
Problem Description
Given an array nums
, you need to find the total number of subsequences that have an odd sum. A subsequence is formed by deleting some (possibly zero) elements from the original array while maintaining the relative order of the remaining elements.
For example, if nums = [1, 2, 3]
, the subsequences with odd sums would be: [1]
, [3]
, [1, 2]
, [2, 3]
, and [1, 2, 3]
.
Since the number of such subsequences can be very large, return the answer modulo 10^9 + 7
.
The solution uses dynamic programming to track two states:
f[0]
: Count of subsequences with even sumf[1]
: Count of subsequences with odd sum
When processing each element x
in the array:
If x
is odd:
- New even-sum subsequences = previous even-sum subsequences + (previous odd-sum subsequences combined with
x
) - New odd-sum subsequences = (previous even-sum subsequences combined with
x
) + previous odd-sum subsequences + subsequence containing onlyx
If x
is even:
- New even-sum subsequences = previous even-sum subsequences + (previous even-sum subsequences combined with
x
) + subsequence containing onlyx
- New odd-sum subsequences = previous odd-sum subsequences + (previous odd-sum subsequences combined with
x
)
The final answer is f[1]
, representing the total count of subsequences with odd sums.
Intuition
The key insight is that when building subsequences, we need to track how adding each new element affects the parity (odd/even nature) of existing subsequence sums.
Think about what happens when we encounter a new element. For each existing subsequence, we have two choices: either include this element or skip it. If we skip it, the subsequence sum remains unchanged. If we include it, the parity of the sum depends on both the current element's parity and the existing subsequence's sum parity.
The parity rules are straightforward:
- Even + Even = Even
- Odd + Odd = Even
- Even + Odd = Odd
- Odd + Even = Odd
This suggests we should maintain two counters: one for subsequences with even sums and one for subsequences with odd sums. As we process each element, we update these counters based on how the new element would change the parity.
When we see an odd number:
- All previous even-sum subsequences become odd when we append this number
- All previous odd-sum subsequences become even when we append this number
- We also create one new odd-sum subsequence containing just this element
When we see an even number:
- All previous even-sum subsequences remain even when we append this number
- All previous odd-sum subsequences remain odd when we append this number
- We also create one new even-sum subsequence containing just this element
By tracking these two states throughout the array traversal, we can efficiently count all subsequences with odd sums without explicitly generating them. The beauty of this approach is that it reduces an exponential problem (generating all 2^n
subsequences) to a linear time solution with just two state variables.
Learn more about Math, Dynamic Programming and Combinatorics patterns.
Solution Approach
We implement a dynamic programming solution using two state variables to track the count of subsequences by their sum parity.
Initialization:
- Create an array
f
with two elements:f[0]
for even-sum subsequences count andf[1]
for odd-sum subsequences count - Initially, both are set to 0 since we haven't processed any elements yet
- Define
mod = 10^9 + 7
for modulo operations
Processing Each Element:
For each number x
in the array, we update our counters based on whether x
is odd or even.
Case 1: When x
is odd (x % 2 == 1
):
The update formulas are:
f[0] = (f[0] + f[1]) % mod f[1] = (f[0] + f[1] + 1) % mod
- New even-sum count: Previous even-sum subsequences (not including
x
) + previous odd-sum subsequences that become even when we add oddx
- New odd-sum count: Previous odd-sum subsequences (not including
x
) + previous even-sum subsequences that become odd when we add oddx
+ 1 (the subsequence containing onlyx
)
Note: We use simultaneous assignment in Python to update both values using the old values of f[0]
and f[1]
.
Case 2: When x
is even (x % 2 == 0
):
The update formulas are:
f[0] = (f[0] + f[0] + 1) % mod f[1] = (f[1] + f[1]) % mod
- New even-sum count: Previous even-sum subsequences (not including
x
) + previous even-sum subsequences withx
added (sum stays even) + 1 (the subsequence containing onlyx
) - New odd-sum count: Previous odd-sum subsequences (not including
x
) + previous odd-sum subsequences withx
added (sum stays odd)
Final Result:
After processing all elements, f[1]
contains the total count of subsequences with odd sums, which is our answer.
The time complexity is O(n)
where n
is the length of the array, and the space complexity is O(1)
as we only use two variables to maintain state.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with nums = [1, 2, 3]
.
Initial state:
f[0] = 0
(even-sum subsequences)f[1] = 0
(odd-sum subsequences)
Step 1: Process element 1 (odd)
- Since 1 is odd, we apply the odd number rules
- New
f[0] = (0 + 0) % mod = 0
- New
f[1] = (0 + 0 + 1) % mod = 1
- Current subsequences:
[1]
with sum 1 (odd) - State:
f[0] = 0
,f[1] = 1
Step 2: Process element 2 (even)
- Since 2 is even, we apply the even number rules
- New
f[0] = (0 + 0 + 1) % mod = 1
- New
f[1] = (1 + 1) % mod = 2
- Current subsequences:
- Even sum:
[2]
(sum = 2) - Odd sum:
[1]
(sum = 1),[1,2]
(sum = 3)
- Even sum:
- State:
f[0] = 1
,f[1] = 2
Step 3: Process element 3 (odd)
- Since 3 is odd, we apply the odd number rules
- Using simultaneous assignment:
- New
f[0] = (1 + 2) % mod = 3
- New
f[1] = (1 + 2 + 1) % mod = 4
- New
- Current subsequences:
- Even sum:
[2]
,[1,3]
,[1,2,3]
(3 total) - Odd sum:
[1]
,[3]
,[1,2]
,[2,3]
(4 total)
- Even sum:
- State:
f[0] = 3
,f[1] = 4
Result: The answer is f[1] = 4
, representing 4 subsequences with odd sums.
Let's verify our answer:
[1]
: sum = 1 (odd) ✓[3]
: sum = 3 (odd) ✓[1,2]
: sum = 3 (odd) ✓[2,3]
: sum = 5 (odd) ✓[1,2,3]
: sum = 6 (even)[2]
: sum = 2 (even)[1,3]
: sum = 4 (even)
Indeed, we have exactly 4 subsequences with odd sums!
Solution Implementation
1class Solution:
2 def subsequenceCount(self, nums: List[int]) -> int:
3 MOD = 10**9 + 7
4
5 # Dynamic programming states:
6 # even_sum_count: count of subsequences with even sum of odd numbers
7 # odd_sum_count: count of subsequences with odd sum of odd numbers
8 even_sum_count = 0
9 odd_sum_count = 0
10
11 for num in nums:
12 if num % 2 == 1: # Current number is odd
13 # When adding an odd number:
14 # - Subsequences with even sum become odd sum
15 # - Subsequences with odd sum become even sum
16 # - We can also start a new subsequence with just this odd number
17 new_even_sum = (even_sum_count + odd_sum_count) % MOD
18 new_odd_sum = (even_sum_count + odd_sum_count + 1) % MOD
19
20 even_sum_count = new_even_sum
21 odd_sum_count = new_odd_sum
22 else: # Current number is even
23 # When adding an even number:
24 # - Parity of sum doesn't change
25 # - We can extend existing subsequences or start new ones
26 new_even_sum = (even_sum_count + even_sum_count + 1) % MOD
27 new_odd_sum = (odd_sum_count + odd_sum_count) % MOD
28
29 even_sum_count = new_even_sum
30 odd_sum_count = new_odd_sum
31
32 # Return count of subsequences with odd sum of odd numbers
33 return odd_sum_count
34
1class Solution {
2 public int subsequenceCount(int[] nums) {
3 // Modulo value for preventing integer overflow
4 final int MOD = (int) 1e9 + 7;
5
6 // Dynamic programming states
7 // dpState[0]: count of subsequences with even sum of odd numbers
8 // dpState[1]: count of subsequences with odd sum of odd numbers
9 int[] dpState = new int[2];
10
11 // Process each number in the array
12 for (int currentNum : nums) {
13 // Create new state array for this iteration
14 int[] newState = new int[2];
15
16 if (currentNum % 2 == 1) {
17 // Current number is odd
18 // Adding an odd number flips the parity of the sum
19
20 // Even sum: previous odd sums become even when adding this odd number
21 newState[0] = (dpState[0] + dpState[1]) % MOD;
22
23 // Odd sum: previous even sums become odd, plus starting new subsequence with just this number
24 newState[1] = (dpState[0] + dpState[1] + 1) % MOD;
25 } else {
26 // Current number is even
27 // Adding an even number doesn't change the parity of odd number sums
28
29 // Even sum: keep existing even sums, double them (include/exclude current),
30 // plus new subsequence with just this even number
31 newState[0] = (dpState[0] + dpState[0] + 1) % MOD;
32
33 // Odd sum: keep existing odd sums, double them (include/exclude current)
34 newState[1] = (dpState[1] + dpState[1]) % MOD;
35 }
36
37 // Update state for next iteration
38 dpState = newState;
39 }
40
41 // Return count of subsequences with odd sum of odd numbers
42 return dpState[1];
43 }
44}
45
1class Solution {
2public:
3 int subsequenceCount(vector<int>& nums) {
4 const int MOD = 1e9 + 7;
5
6 // Dynamic programming state arrays
7 // dpState[0]: count of subsequences with even sum of odd numbers
8 // dpState[1]: count of subsequences with odd sum of odd numbers
9 vector<int> dpState(2, 0);
10
11 // Process each number in the input array
12 for (int currentNum : nums) {
13 // Create new state array for current iteration
14 vector<int> newState(2, 0);
15
16 if (currentNum % 2 == 1) { // Current number is odd
17 // Adding an odd number to subsequences with even count gives odd count
18 newState[0] = (dpState[0] + dpState[1]) % MOD;
19
20 // Adding an odd number to subsequences with odd count gives even count
21 // Plus 1 for starting a new subsequence with just this odd number
22 newState[1] = (dpState[0] + dpState[1] + 1) % MOD;
23 } else { // Current number is even
24 // Adding an even number doesn't change the odd count parity
25 // Can extend existing even-count subsequences or start new one
26 newState[0] = (dpState[0] + dpState[0] + 1) % MOD;
27
28 // Extend existing odd-count subsequences (parity unchanged)
29 newState[1] = (dpState[1] + dpState[1]) % MOD;
30 }
31
32 // Update state for next iteration
33 dpState = newState;
34 }
35
36 // Return count of subsequences with odd sum of odd numbers
37 return dpState[1];
38 }
39};
40
1/**
2 * Counts special subsequences based on odd/even number patterns
3 * using dynamic programming approach
4 * @param nums - Array of numbers to process
5 * @returns Count of valid subsequences modulo 10^9 + 7
6 */
7function subsequenceCount(nums: number[]): number {
8 const MOD: number = 1e9 + 7;
9
10 // Dynamic programming state array
11 // dpState[0]: count of subsequences with even sum/property
12 // dpState[1]: count of subsequences with odd sum/property
13 let dpState: number[] = [0, 0];
14
15 // Process each number in the input array
16 for (const currentNum of nums) {
17 // Create new state array for current iteration
18 const nextState: number[] = [0, 0];
19
20 if (currentNum % 2 === 1) {
21 // Current number is odd
22 // Even state: combine previous even and odd states
23 nextState[0] = (dpState[0] + dpState[1]) % MOD;
24 // Odd state: combine previous states and add new subsequence starting here
25 nextState[1] = (dpState[0] + dpState[1] + 1) % MOD;
26 } else {
27 // Current number is even
28 // Even state: extend even subsequences or start new subsequence
29 nextState[0] = (dpState[0] + dpState[0] + 1) % MOD;
30 // Odd state: extend odd subsequences only
31 nextState[1] = (dpState[1] + dpState[1]) % MOD;
32 }
33
34 // Update state for next iteration
35 dpState = nextState;
36 }
37
38 // Return count of subsequences with odd property
39 return dpState[1];
40}
41
Time and Space Complexity
The time complexity is O(n)
, where n
is the length of the array nums
. This is because the algorithm iterates through the array exactly once with a single for loop, and within each iteration, it performs only constant-time operations (modulo arithmetic and variable assignments).
The space complexity is O(1)
. The algorithm uses only a fixed amount of extra space regardless of the input size - specifically, it maintains an array f
of size 2 and a constant mod
variable. The space usage does not grow with the size of the input array nums
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect State Update Order
One of the most common mistakes is updating the states in the wrong order, causing the use of already-modified values instead of the original values from the previous iteration.
Incorrect Implementation:
if num % 2 == 1: even_sum_count = (even_sum_count + odd_sum_count) % MOD odd_sum_count = (even_sum_count + odd_sum_count + 1) % MOD # Bug: uses modified even_sum_count
In this buggy code, when updating odd_sum_count
, we're using the newly updated even_sum_count
instead of the original value, leading to incorrect results.
Solution: Use temporary variables or simultaneous assignment to ensure both updates use the original values:
if num % 2 == 1: new_even = (even_sum_count + odd_sum_count) % MOD new_odd = (even_sum_count + odd_sum_count + 1) % MOD even_sum_count, odd_sum_count = new_even, new_odd
Or using Python's tuple unpacking:
if num % 2 == 1: even_sum_count, odd_sum_count = (even_sum_count + odd_sum_count) % MOD, \ (even_sum_count + odd_sum_count + 1) % MOD
2. Misunderstanding the Problem Statement
Another pitfall is misinterpreting what constitutes an "odd sum subsequence." Some might mistakenly think it refers to:
- Subsequences with an odd number of elements
- Subsequences containing only odd numbers
- Subsequences where the count of odd numbers is odd
Clarification: The problem asks for subsequences where the sum of all elements is odd, regardless of how many elements are in the subsequence or whether they are odd or even.
3. Forgetting the Modulo Operation
Since the result can be very large, forgetting to apply modulo at each step can cause integer overflow in languages with fixed integer sizes, or incorrect results when the final modulo is applied to an already overflowed value.
Incorrect:
even_sum_count = even_sum_count + odd_sum_count # Missing modulo
Correct:
even_sum_count = (even_sum_count + odd_sum_count) % MOD
4. Incorrect Initial State for Even Numbers
When processing an even number, some might forget to account for the subsequence containing only that even number (which has an even sum), missing the +1
in the even count update.
Incorrect:
if num % 2 == 0: even_sum_count = (even_sum_count * 2) % MOD # Missing +1
Correct:
if num % 2 == 0: even_sum_count = (even_sum_count * 2 + 1) % MOD
Which of the tree traversal order can be used to obtain elements in a binary search tree in sorted order?
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
What is Dynamic Programming Prerequisite DFS problems dfs_intro Backtracking problems backtracking Memoization problems memoization_intro Pruning problems backtracking_pruning Dynamic programming is an algorithmic optimization technique that breaks down a complicated problem into smaller overlapping sub problems in a recursive manner and uses solutions to the sub problems to construct a solution
Backtracking Template Prereq DFS with States problems dfs_with_states Combinatorial search problems Combinatorial search problems involve finding groupings and assignments of objects that satisfy certain conditions Finding all permutations combinations subsets and solving Sudoku are classic combinatorial problems The time complexity of combinatorial problems often grows rapidly with the size of
Want a Structured Path to Master System Design Too? Don’t Miss This!