Facebook Pixel

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 sum
  • f[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 only x

If x is even:

  • New even-sum subsequences = previous even-sum subsequences + (previous even-sum subsequences combined with x) + subsequence containing only x
  • 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.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

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 and f[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 odd x
  • New odd-sum count: Previous odd-sum subsequences (not including x) + previous even-sum subsequences that become odd when we add odd x + 1 (the subsequence containing only x)

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 with x added (sum stays even) + 1 (the subsequence containing only x)
  • New odd-sum count: Previous odd-sum subsequences (not including x) + previous odd-sum subsequences with x 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 Evaluator

Example 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)
  • 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
  • Current subsequences:
    • Even sum: [2], [1,3], [1,2,3] (3 total)
    • Odd sum: [1], [3], [1,2], [2,3] (4 total)
  • 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
Discover Your Strengths and Weaknesses: Take Our 3-Minute Quiz to Tailor Your Study Plan:

Which of the tree traversal order can be used to obtain elements in a binary search tree in sorted order?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More