Facebook Pixel

3247. Number of Subsequences with Odd Sum 🔒


Problem Description

Given an array nums, return the number of subsequences with an odd sum of elements. Since the answer may be very large, return it modulo (10^9 + 7).

Intuition

To solve the problem of counting subsequences with an odd sum, we can use a dynamic programming approach.

We keep track of two numbers: f[0] for the number of subsequences with an even sum and f[1] for the number of subsequences with an odd sum. Initially, both are set to 0 because there are no subsequences yet.

As we traverse through each element of the input array nums, we need to update these two counters based on whether the current element is odd or even:

  1. If the current element x is odd:

    • Adding x to any existing subsequence with an even sum will result in an odd sum. Thus, the new number of subsequences with an odd sum (f[1]) becomes the old count of even-sum subsequences plus the current count of odd-sum subsequences, plus one for the new subsequence consisting only of this element.
    • Similarly, adding x to any existing subsequence with an odd sum will result in an even sum, hence the new number of even-sum subsequences (f[0]) becomes the old count of odd-sum subsequences plus the current count of even-sum subsequences.
  2. If the current element x is even:

    • Adding x to any existing subsequence with an even sum will still result in an even sum, so f[0] is updated to include twice the number of existing even-sum subsequences plus one for the new subsequence consisting only of this element.
    • Adding x to any existing subsequence with an odd sum remains odd, so f[1] is updated to twice its current count.

Finally, return f[1] as it represents the count of subsequences with an odd sum.

Learn more about Math, Dynamic Programming and Combinatorics patterns.

Solution Approach

To achieve the goal of counting subsequences with an odd sum efficiently, we utilize a dynamic programming approach as outlined in the reference solution. Here's a step-by-step explanation:

  1. Variables Initialization:

    • We initialize f as a list of two integers: f[0] and f[1], both initially set to 0. f[0] will track the count of subsequences with an even sum, while f[1] will count those with an odd sum.
  2. Iterate through the Array:

    • For each element x in the array nums, we need to update our counts depending on whether x is odd or even.
  3. If x is Odd:

    • Update f[0] to the sum of the previous f[0] and f[1], as adding an odd number to an even sum makes it odd, and adding it to an odd sum makes it even:
      f[0] = (f[0] + f[1]) % mod
    • Update f[1] by adding to it the sum of the old f[0] plus f[1] plus one to account for subsequences containing just the number x:
      f[1] = (f[0] + f[1] + 1) % mod
  4. If x is Even:

    • Update f[0] by doubling the previous f[0] and adding one, as adding an even number retains the even nature of sums:
      f[0] = (f[0] + f[0] + 1) % mod
    • Update f[1] by doubling the previous f[1], since adding an even number to an odd sum retains its odd nature:
      f[1] = (f[1] + f[1]) % mod
  5. Modulo Operation:

    • Since the result can be very large, every update to f[0] and f[1] is followed by taking modulo 10^9 + 7 to prevent overflow and maintain compliance with the problem constraints.
  6. Return the Result:

    • After processing all elements in nums, the variable f[1] holds the number of subsequences with an odd sum. Return this value as the final result:
      return f[1]

This dynamic programming solution ensures we efficiently calculate the number of subsequences with odd sums in linear time complexity relative to the size of the input array, nums.

Ready to land your dream job?

Unlock your dream job with a 2-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the solution approach with a small example.

Consider the array nums = [1, 2, 3].

  1. Initialization:

    • Begin with f = [0, 0], where f[0] is the count of subsequences with an even sum, and f[1] is the count with an odd sum.
  2. Process Element 1 (odd):

    • Before processing, f = [0, 0].
    • Add 1 to existing even sum sequences (f[0]): No impact since no even sequences exist yet.
    • Add 1 to existing odd sum sequences (f[1]): No impact since no odd sequences exist yet.
    • Add sequence [1]: Increase odd sum sequences (f[1]) by 1.
    • After processing, f = [0, 1].
  3. Process Element 2 (even):

    • Before processing, f = [0, 1].
    • Add 2 to existing even sum sequences (f[0]): Still results in even sums, double f[0] and add 1 (new sequence [2]).
    • Add 2 to existing odd sum sequences (f[1]): Results in odd sums, double f[1].
    • Update: f[0] becomes 0*2 + 1 = 1; f[1] becomes 1*2 = 2.
    • After processing, f = [1, 2].
  4. Process Element 3 (odd):

    • Before processing, f = [1, 2].
    • Add 3 to existing even sum sequences (f[0]): Results in odd sums, use old f[0] + f[1].
    • Add 3 to existing odd sum sequences (f[1]): Results in even sums, double f[1].
    • Add sequence [3]: Increase odd sum (f[1]) by 1.
    • Calculation:
      • New f[0] = 1 + 2 = 3.
      • New f[1] = 1 + 2 + 1 = 4.
    • After processing, f = [3, 4].
  5. Final result:

    • The number of subsequences with an odd sum is held in f[1], which equals 4.

The steps above illustrate how the dynamic programming solution processes each element in nums by updating the count of subsequences with even and odd sums.

Solution Implementation

1from typing import List
2
3class Solution:
4    def subsequenceCount(self, nums: List[int]) -> int:
5        # Define the modulus to prevent integer overflow
6        mod = 10**9 + 7
7        # Create an array 'f' to store results of subsequences 
8        # f[0] for even product subsequences, f[1] for odd product subsequences
9        f = [0] * 2
10      
11        # Iterate over each number in the input list
12        for x in nums:
13            # If the number is odd
14            if x % 2:
15                # Both even and odd subsequences are affected:
16                # f[0] becomes a combination of old f[0] and f[1] (even product)
17                # f[1] gets incremented by 1 to account for the current number 
18                f[0], f[1] = (f[0] + f[1]) % mod, (f[0] + f[1] + 1) % mod
19            else:
20                # If the number is even:
21                # f[0] is twice f[0], plus a new subsequence containing the single even number
22                # f[1] is twice f[1] (odd product remains the same)
23                f[0], f[1] = (f[0] * 2 + 1) % mod, (f[1] * 2) % mod
24              
25        # Return the count of subsequences with odd product
26        return f[1]
27
1class Solution {
2    public int subsequenceCount(int[] nums) {
3        final int MOD = (int) 1e9 + 7; // Define the modulo constant
4        int[] f = new int[2]; // Initialize the array to track counts of subsequences
5
6        // Iterate through each number in the given array
7        for (int num : nums) {
8            int[] g = new int[2]; // Temporary array for the new count values
9
10            // Check if the current number is odd
11            if (num % 2 == 1) {
12                // Update counts for subsequences ending with an odd number
13                g[0] = (f[0] + f[1]) % MOD; // Sum of previous subsequences' counts
14                g[1] = (f[0] + f[1] + 1) % MOD; // Additional count for sequences including the current number
15            } else {
16                // Update counts for subsequences ending with an even number
17                g[0] = (f[0] * 2 + 1) % MOD; // Doubling counts from f[0] and adding one
18                g[1] = (f[1] * 2) % MOD; // Doubling counts from f[1]
19            }
20
21            f = g; // Move the new counts to f
22        }
23
24        // Return the count of subsequences with an odd sum
25        return f[1];
26    }
27}
28
1class Solution {
2public:
3    int subsequenceCount(vector<int>& nums) {
4        const int MOD = 1e9 + 7;  // Declare a constant for the modulus operation
5        vector<int> subsequenceSum(2);  // Initialize a vector for storing subsequence sums
6     
7        for (int number : nums) {  // Iterate through each number in the input vector
8            vector<int> newSubsequenceSum(2);  // Create a new vector for the current state
9          
10            if (number % 2 == 1) {  // Check if the number is odd
11                // Update the counts of subsequences ending in odd or even sums
12                newSubsequenceSum[0] = (subsequenceSum[0] + subsequenceSum[1]) % MOD;
13                newSubsequenceSum[1] = (subsequenceSum[0] + subsequenceSum[1] + 1) % MOD;
14            } else {
15                // When the number is even, update the subsequences in a different manner
16                newSubsequenceSum[0] = (subsequenceSum[0] + subsequenceSum[0] + 1) % MOD;
17                newSubsequenceSum[1] = (subsequenceSum[1] + subsequenceSum[1]) % MOD;
18            }
19          
20            subsequenceSum = newSubsequenceSum;  // Update the previous state with the current state
21        }
22      
23        return subsequenceSum[1];  // Return the count of subsequences with odd sums
24    }
25};
26
1function subsequenceCount(nums: number[]): number {
2    const mod = 1e9 + 7; // Define the mod value to ensure results do not overflow
3    let f = [0, 0]; // Initialize an array f where f[0] and f[1] track even and odd subsequences
4
5    // Iterate over each number in the input array
6    for (const x of nums) {
7        const g = [0, 0]; // Create a new array g to store the current sequence state's count
8
9        if (x % 2 === 1) {
10            // If the number is odd:
11            // All current subsequences can be extended by this odd number to form new even subsequences g[0]
12            // All current subsequences can also be extended to form new odd subsequences g[1], plus the number itself as a new subsequence
13            g[0] = (f[0] + f[1]) % mod;
14            g[1] = (f[0] + f[1] + 1) % mod;
15        } else {
16            // If the number is even:
17            // All current even subsequences f[0] can be extended to remain even, plus the number itself as a new even subsequence
18            g[0] = (f[0] + f[0] + 1) % mod;
19            // All current odd subsequences f[1] can be extended to remain odd
20            g[1] = (f[1] + f[1]) % mod;
21        }
22
23        // Update f to the current g values for the next iteration
24        f = g;
25    }
26
27    // Return the count of odd subsequences, which is stored in f[1]
28    return f[1];
29}
30

Time and Space Complexity

The time complexity of the code is O(n), where n is the length of the array nums. This is because the code iterates through each element of the input array exactly once.

The space complexity of the code is O(1), as it uses a fixed amount of additional space (the list f with two elements) regardless of the input size.

Learn more about how to find time and space complexity quickly.


Discover Your Strengths and Weaknesses: Take Our 2-Minute Quiz to Tailor Your Study Plan:
Question 1 out of 10

Which data structure is used to implement priority queue?


Recommended Readings

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


Load More