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:
-
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.
- Adding
-
If the current element
x
is even:- Adding
x
to any existing subsequence with an even sum will still result in an even sum, sof[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, sof[1]
is updated to twice its current count.
- Adding
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:
-
Variables Initialization:
- We initialize
f
as a list of two integers:f[0]
andf[1]
, both initially set to 0.f[0]
will track the count of subsequences with an even sum, whilef[1]
will count those with an odd sum.
- We initialize
-
Iterate through the Array:
- For each element
x
in the arraynums
, we need to update our counts depending on whetherx
is odd or even.
- For each element
-
If
x
is Odd:- Update
f[0]
to the sum of the previousf[0]
andf[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 oldf[0]
plusf[1]
plus one to account for subsequences containing just the numberx
:f[1] = (f[0] + f[1] + 1) % mod
- Update
-
If
x
is Even:- Update
f[0]
by doubling the previousf[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 previousf[1]
, since adding an even number to an odd sum retains its odd nature:f[1] = (f[1] + f[1]) % mod
- Update
-
Modulo Operation:
- Since the result can be very large, every update to
f[0]
andf[1]
is followed by taking modulo10^9 + 7
to prevent overflow and maintain compliance with the problem constraints.
- Since the result can be very large, every update to
-
Return the Result:
- After processing all elements in
nums
, the variablef[1]
holds the number of subsequences with an odd sum. Return this value as the final result:return f[1]
- After processing all elements in
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 EvaluatorExample Walkthrough
Let's walk through the solution approach with a small example.
Consider the array nums = [1, 2, 3]
.
-
Initialization:
- Begin with
f = [0, 0]
, wheref[0]
is the count of subsequences with an even sum, andf[1]
is the count with an odd sum.
- Begin with
-
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]
.
- Before processing,
-
Process Element 2 (even):
- Before processing,
f = [0, 1]
. - Add 2 to existing even sum sequences (
f[0]
): Still results in even sums, doublef[0]
and add 1 (new sequence [2]). - Add 2 to existing odd sum sequences (
f[1]
): Results in odd sums, doublef[1]
. - Update:
f[0]
becomes0*2 + 1 = 1
;f[1]
becomes1*2 = 2
. - After processing,
f = [1, 2]
.
- Before processing,
-
Process Element 3 (odd):
- Before processing,
f = [1, 2]
. - Add 3 to existing even sum sequences (
f[0]
): Results in odd sums, use oldf[0] + f[1]
. - Add 3 to existing odd sum sequences (
f[1]
): Results in even sums, doublef[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
.
- New
- After processing,
f = [3, 4]
.
- Before processing,
-
Final result:
- The number of subsequences with an odd sum is held in
f[1]
, which equals 4.
- The number of subsequences with an odd sum is held in
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.
Which data structure is used to implement priority queue?
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!