2495. Number of Subarrays Having Even Product đ
Problem Description
You are given a 0-indexed integer array nums
. Your task is to count how many subarrays of nums
have an even product.
A subarray is a contiguous sequence of elements from the array. The product of a subarray is the result of multiplying all elements within that subarray together. A product is even if it's divisible by 2.
For example, if nums = [1, 2, 3]
:
- Subarray
[1]
has product 1 (odd) - Subarray
[2]
has product 2 (even) - Subarray
[3]
has product 3 (odd) - Subarray
[1, 2]
has product 2 (even) - Subarray
[2, 3]
has product 6 (even) - Subarray
[1, 2, 3]
has product 6 (even)
So there are 4 subarrays with even products.
The key insight is that a product is even if and only if at least one number in the subarray is even. The solution tracks the position of the most recent even number encountered (last
). For each position i
, the number of subarrays ending at position i
that have an even product equals last + 1
(since any subarray that includes the even number at position last
will have an even product).
Intuition
To understand this problem, let's first think about when a product becomes even. A product is even when at least one of its factors is even. This means for any subarray to have an even product, it just needs to contain at least one even number.
Now, let's think about counting subarrays ending at each position. For any position i
, we want to know: how many subarrays ending at position i
have an even product?
The key observation is that if we know where the most recent even number is located (let's call this position last
), then any subarray that:
- Ends at position
i
- Starts at or after position
last
will definitely have an even product because it includes that even number at position last
.
For example, if we have nums = [1, 3, 2, 5]
and we're at position i = 3
(value 5):
- The most recent even number is at position
last = 2
(value 2) - Subarrays ending at position 3 that have even products are:
[2, 5]
starting from position 2[3, 2, 5]
starting from position 1[1, 3, 2, 5]
starting from position 0
- That's exactly
last + 1 = 2 + 1 = 3
subarrays
This pattern holds because we can start our subarray from any position between 0 and last
(inclusive), and as long as we end at the current position i
, we'll include that even number at position last
, making the product even.
If we haven't encountered any even number yet (last = -1
), then no subarray ending at the current position can have an even product, which aligns with our formula: last + 1 = -1 + 1 = 0
.
Learn more about Math and Dynamic Programming patterns.
Solution Approach
The solution uses a single-pass algorithm with constant space complexity. We maintain two variables:
ans
: accumulates the total count of subarrays with even productslast
: tracks the index of the most recent even number encountered (initialized to-1
)
Here's how the algorithm works step by step:
-
Initialize variables: Set
ans = 0
to store our result andlast = -1
to indicate we haven't found an even number yet. -
Iterate through the array: For each element at index
i
with valuev
:- Check if current element is even: If
v % 2 == 0
, updatelast = i
since we've found a new even number - Count subarrays: Add
last + 1
to our answer. This represents the number of subarrays ending at positioni
that have an even product
- Check if current element is even: If
-
Return the result: After processing all elements,
ans
contains the total count.
Let's trace through an example with nums = [1, 2, 3, 4]
:
i = 0, v = 1
(odd):last
remains-1
, add(-1) + 1 = 0
toans
. Total:0
i = 1, v = 2
(even): Updatelast = 1
, add1 + 1 = 2
toans
. Total:2
i = 2, v = 3
(odd):last
remains1
, add1 + 1 = 2
toans
. Total:4
i = 3, v = 4
(even): Updatelast = 3
, add3 + 1 = 4
toans
. Total:8
The formula last + 1
works because:
- If
last = -1
(no even number seen yet), we add0
(no valid subarrays) - If
last >= 0
, we can formlast + 1
subarrays by starting from positions0, 1, ..., last
and ending at the current positioni
This approach efficiently counts all subarrays with even products in O(n)
time and O(1)
space.
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 a concrete example with nums = [3, 1, 2, 5]
to illustrate how the solution works.
Initial Setup:
ans = 0
(total count of subarrays with even products)last = -1
(no even number seen yet)
Step 1: Process index 0, value = 3 (odd)
- 3 is odd, so
last
stays-1
- Subarrays ending at index 0:
[3]
- None have even products (no even numbers included)
- Add
last + 1 = -1 + 1 = 0
toans
- Running total:
ans = 0
Step 2: Process index 1, value = 1 (odd)
- 1 is odd, so
last
stays-1
- Subarrays ending at index 1:
[1]
,[3,1]
- None have even products (still no even numbers)
- Add
last + 1 = -1 + 1 = 0
toans
- Running total:
ans = 0
Step 3: Process index 2, value = 2 (even)
- 2 is even, so update
last = 2
- Subarrays ending at index 2:
[2]
,[1,2]
,[3,1,2]
- All three include the even number at index 2, so all have even products
- Add
last + 1 = 2 + 1 = 3
toans
- Running total:
ans = 3
Step 4: Process index 3, value = 5 (odd)
- 5 is odd, so
last
stays2
- Subarrays ending at index 3:
[5]
,[2,5]
,[1,2,5]
,[3,1,2,5]
- The last three include the even number at index 2, so they have even products
- Add
last + 1 = 2 + 1 = 3
toans
- Running total:
ans = 6
Final Result: 6 subarrays with even products
The key insight demonstrated here is that once we encounter an even number at position last
, any subarray that includes this position will have an even product. For each new position, we can form exactly last + 1
such subarrays by choosing different starting positions (from 0 to last
).
Solution Implementation
1class Solution:
2 def evenProduct(self, nums: List[int]) -> int:
3 # Count total number of subarrays with even product
4 total_count = 0
5 # Track the index of the most recent even number seen
6 last_even_index = -1
7
8 # Iterate through each element with its index
9 for current_index, value in enumerate(nums):
10 # If current element is even, update the last even index
11 if value % 2 == 0:
12 last_even_index = current_index
13
14 # Add count of subarrays ending at current index that have even product
15 # These are all subarrays from index 0 to last_even_index that extend to current_index
16 # If last_even_index is -1 (no even number seen), then last_even_index + 1 = 0 (no subarrays)
17 total_count += last_even_index + 1
18
19 return total_count
20
1class Solution {
2 /**
3 * Counts the number of subarrays that contain at least one even number.
4 *
5 * @param nums the input array of integers
6 * @return the total count of subarrays with at least one even element
7 */
8 public long evenProduct(int[] nums) {
9 long totalCount = 0;
10 int lastEvenIndex = -1; // Index of the most recent even number encountered
11
12 // Iterate through each element in the array
13 for (int i = 0; i < nums.length; i++) {
14 // Check if current element is even
15 if (nums[i] % 2 == 0) {
16 lastEvenIndex = i; // Update the position of the last even number
17 }
18
19 // Add the count of valid subarrays ending at index i
20 // If lastEvenIndex is -1, no even numbers seen yet, so add 0
21 // Otherwise, add (lastEvenIndex + 1) which represents all subarrays
22 // ending at i that start at or after index 0 and contain the even number
23 totalCount += lastEvenIndex + 1;
24 }
25
26 return totalCount;
27 }
28}
29
1class Solution {
2public:
3 long long evenProduct(vector<int>& nums) {
4 long long totalCount = 0;
5 int lastEvenIndex = -1; // Index of the most recent even number
6
7 // Iterate through each element in the array
8 for (int i = 0; i < nums.size(); ++i) {
9 // Check if current number is even
10 if (nums[i] % 2 == 0) {
11 lastEvenIndex = i; // Update position of last even number
12 }
13
14 // Add count of subarrays ending at index i that contain at least one even number
15 // lastEvenIndex + 1 represents the number of valid starting positions
16 // (from index 0 to lastEvenIndex) that form subarrays with even product
17 totalCount += lastEvenIndex + 1;
18 }
19
20 return totalCount;
21 }
22};
23
1function evenProduct(nums: number[]): number {
2 let totalCount: number = 0;
3 let lastEvenIndex: number = -1; // Index of the most recent even number
4
5 // Iterate through each element in the array
6 for (let i = 0; i < nums.length; i++) {
7 // Check if current number is even
8 if (nums[i] % 2 === 0) {
9 lastEvenIndex = i; // Update position of last even number
10 }
11
12 // Add count of subarrays ending at index i that contain at least one even number
13 // lastEvenIndex + 1 represents the number of valid starting positions
14 // (from index 0 to lastEvenIndex) that form subarrays with even product
15 totalCount += lastEvenIndex + 1;
16 }
17
18 return totalCount;
19}
20
Time and Space Complexity
The time complexity is O(n)
, where n
is the length of the array nums
. The algorithm iterates through the array exactly once using a single for loop with enumerate(nums)
. Each operation inside the loop (checking if a number is even with modulo operation, updating the last
variable, and adding to ans
) takes constant time O(1)
.
The space complexity is O(1)
. The algorithm only uses a fixed amount of extra space regardless of the input size. It maintains just two variables: ans
to store the result and last
to track the index of the most recent even number. These variables require constant space that doesn't grow with the input size.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Confusing the Problem with Counting Odd Products
A common mistake is trying to count odd products and then subtract from the total number of subarrays. While this approach can work, it adds unnecessary complexity and is more error-prone.
Incorrect approach:
def evenProduct(self, nums: List[int]) -> int:
n = len(nums)
total_subarrays = n * (n + 1) // 2
odd_count = 0
consecutive_odds = 0
for num in nums:
if num % 2 == 1:
consecutive_odds += 1
odd_count += consecutive_odds
else:
consecutive_odds = 0
return total_subarrays - odd_count # This logic is flawed
Why it fails: The logic for counting odd product subarrays is more complex than it appears. You need to track consecutive odd segments properly, which is harder to implement correctly.
2. Off-by-One Error in Index Calculation
Developers might forget to add 1 to last_even_index
when counting subarrays, or might initialize last_even_index
to 0 instead of -1.
Incorrect initialization:
def evenProduct(self, nums: List[int]) -> int:
total_count = 0
last_even_index = 0 # Wrong! Should be -1
for current_index, value in enumerate(nums):
if value % 2 == 0:
last_even_index = current_index
total_count += last_even_index # Wrong! Should be last_even_index + 1
return total_count
Why it fails: Starting with last_even_index = 0
incorrectly assumes there's an even number at index 0, leading to overcounting when the array starts with odd numbers.
3. Integer Overflow in Other Languages
While Python handles large integers automatically, in languages like Java or C++, the result might overflow for large arrays.
Solution for other languages:
// Use long instead of int in Java
public long evenProduct(int[] nums) {
long totalCount = 0; // Use long to prevent overflow
int lastEvenIndex = -1;
for (int i = 0; i < nums.length; i++) {
if (nums[i] % 2 == 0) {
lastEvenIndex = i;
}
totalCount += lastEvenIndex + 1;
}
return totalCount;
}
4. Misunderstanding Zero Values
If the array contains zeros, some might incorrectly handle them separately, not realizing that zero is even (0 % 2 == 0).
Incorrect special handling:
def evenProduct(self, nums: List[int]) -> int:
total_count = 0
last_even_index = -1
for current_index, value in enumerate(nums):
if value == 0: # Unnecessary special case
# Some incorrect special handling
continue
elif value % 2 == 0:
last_even_index = current_index
total_count += last_even_index + 1
return total_count
Why it fails: Zero is even and should be treated like any other even number. Special handling breaks the algorithm's logic.
5. Using Two Pointers or Nested Loops
Some might overcomplicate the solution with a brute force approach that checks every subarray explicitly.
Inefficient approach:
def evenProduct(self, nums: List[int]) -> int:
count = 0
n = len(nums)
for i in range(n):
has_even = False
for j in range(i, n):
if nums[j] % 2 == 0:
has_even = True
if has_even:
count += 1
return count
Why it's problematic: This O(n²) solution is correct but inefficient. For large arrays, it will cause time limit exceeded errors.
Best Practice: Stick to the elegant O(n) solution that tracks the last even index. It's simpler, more efficient, and less prone to errors.
A person thinks of a number between 1 and 1000. You may ask any number questions to them, provided that the question can be answered with either "yes" or "no".
What is the minimum number of questions you needed to ask so that you are guaranteed to know the number that the person is thinking?
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
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Want a Structured Path to Master System Design Too? Donât Miss This!