LeetCode 3917 - Count Indices With Opposite Parity
The problem gives us an integer array nums of length n. For every index i, we must determine how many indices to its right contain a number with the opposite parity. Parity refers to whether a number is even or odd: - Even numbers have a remainder of 0 when divided by 2.
Difficulty: 🟢 Easy
Topics: Array
Solution
LeetCode 3917 - Count Indices With Opposite Parity
Problem Understanding
The problem gives us an integer array nums of length n. For every index i, we must determine how many indices to its right contain a number with the opposite parity.
Parity refers to whether a number is even or odd:
- Even numbers have a remainder of
0when divided by2. - Odd numbers have a remainder of
1when divided by2.
For a particular index i, its score is the number of indices j such that:
jis strictly greater thaninums[i]andnums[j]have different parity
The output is an array answer where answer[i] contains the score for index i.
For example, if nums[i] is odd, then we need to count how many even numbers appear after position i. Similarly, if nums[i] is even, we need to count how many odd numbers appear after position i.
The constraints are very small:
1 <= nums.length <= 1001 <= nums[i] <= 100
Since the array length is only 100, even quadratic solutions would comfortably fit within the limits. However, it is still useful to identify a more efficient approach.
Some important edge cases include:
- An array containing only one element.
- An array where all numbers are even.
- An array where all numbers are odd.
- Arrays with alternating parity.
- Arrays where the desired opposite parity appears only near the beginning or end.
The problem guarantees that the array is non-empty and all values are positive integers.
Approaches
Brute Force
The most direct solution is to evaluate the score for every index independently.
For each index i, we scan every later index j > i. Whenever nums[i] and nums[j] have opposite parity, we increment the score for i.
This approach is correct because it directly implements the definition of the score given in the problem statement. Every valid pair (i, j) is examined exactly once.
However, for every index we may scan the remainder of the array, resulting in quadratic time complexity.
Optimal Observation
Instead of repeatedly scanning the suffix of the array, we can process the array from right to left.
Suppose we know how many odd and even numbers exist to the right of the current position.
- If the current number is odd, its answer is the number of even values to its right.
- If the current number is even, its answer is the number of odd values to its right.
After computing the answer for the current position, we add the current number to the appropriate parity count so that it becomes part of the suffix for future indices.
This allows every position to be processed in constant time.
Approach Comparison
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n²) | O(1) | Check every pair (i, j) with i < j |
| Optimal | O(n) | O(1) | Maintain counts of odd and even numbers to the right |
Algorithm Walkthrough
Optimal Algorithm
- Create an answer array of length
n, initialized with zeros. - Maintain two counters:
odd_count, the number of odd elements to the right of the current position.even_count, the number of even elements to the right of the current position.
- Start traversing the array from right to left.
- For the current element:
- If it is odd, then every even number already counted in
even_countforms a valid opposite-parity pair. Setanswer[i] = even_count. - If it is even, then every odd number already counted in
odd_countforms a valid opposite-parity pair. Setanswer[i] = odd_count.
- After computing the answer for the current index, update the appropriate parity counter:
- Increment
odd_countif the current value is odd. - Increment
even_countif the current value is even.
- Continue until all indices have been processed.
- Return the completed answer array.
Why it works
When processing index i, the counters contain exactly the numbers that appear strictly to the right of i. Therefore:
odd_countequals the number of odd elements in the suffix(i+1 ... n-1).even_countequals the number of even elements in the suffix(i+1 ... n-1).
If nums[i] is odd, every even number in that suffix contributes one valid pair. If nums[i] is even, every odd number contributes one valid pair. Since the counters always represent the current suffix correctly, each answer is computed exactly according to the problem definition.
Python Solution
class Solution:
def countOppositeParity(self, nums: list[int]) -> list[int]:
n = len(nums)
answer = [0] * n
odd_count = 0
even_count = 0
for i in range(n - 1, -1, -1):
if nums[i] % 2 == 1:
answer[i] = even_count
odd_count += 1
else:
answer[i] = odd_count
even_count += 1
return answer
The implementation begins by creating the result array and initializing counters for odd and even values appearing to the right of the current position.
The array is then traversed from right to left. At each index, the current parity determines which counter represents valid opposite-parity elements. That value becomes the answer for the current index.
After recording the answer, the current element is added to the appropriate counter. This ensures that when earlier indices are processed, the current element is correctly considered part of their suffix.
Finally, the populated answer array is returned.
Go Solution
func countOppositeParity(nums []int) []int {
n := len(nums)
answer := make([]int, n)
oddCount := 0
evenCount := 0
for i := n - 1; i >= 0; i-- {
if nums[i]%2 == 1 {
answer[i] = evenCount
oddCount++
} else {
answer[i] = oddCount
evenCount++
}
}
return answer
}
The Go implementation follows exactly the same logic as the Python version. The result slice is allocated with make, and two integer counters track the number of odd and even elements seen while traversing from right to left.
There are no special concerns regarding integer overflow because the maximum possible answer is at most n - 1, and n <= 100. Go slices are used directly, and there is no distinction that affects correctness between nil and empty slices because the input always contains at least one element.
Worked Examples
Example 1
Input:
nums = [1, 2, 3, 4]
Process from right to left.
| Index | Value | Parity | odd_count Before | even_count Before | answer[i] | odd_count After | even_count After |
|---|---|---|---|---|---|---|---|
| 3 | 4 | Even | 0 | 0 | 0 | 0 | 1 |
| 2 | 3 | Odd | 0 | 1 | 1 | 1 | 1 |
| 1 | 2 | Even | 1 | 1 | 1 | 1 | 2 |
| 0 | 1 | Odd | 1 | 2 | 2 | 2 | 2 |
Final result:
[2, 1, 1, 0]
Example 2
Input:
nums = [1]
Process from right to left.
| Index | Value | Parity | odd_count Before | even_count Before | answer[i] |
|---|---|---|---|---|---|
| 0 | 1 | Odd | 0 | 0 | 0 |
Final result:
[0]
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | Each element is processed exactly once |
| Space | O(1) | Only two counters are used beyond the output array |
The algorithm performs a single pass through the array from right to left. Every iteration executes a constant amount of work, resulting in linear time complexity. Aside from the required output array, only two integer counters are maintained, so the auxiliary space usage is constant.
Test Cases
sol = Solution()
assert sol.countOppositeParity([1, 2, 3, 4]) == [2, 1, 1, 0] # provided example
assert sol.countOppositeParity([1]) == [0] # single element
assert sol.countOppositeParity([2, 4, 6, 8]) == [0, 0, 0, 0] # all even
assert sol.countOppositeParity([1, 3, 5, 7]) == [0, 0, 0, 0] # all odd
assert sol.countOppositeParity([1, 2]) == [1, 0] # minimal opposite parity pair
assert sol.countOppositeParity([2, 1]) == [1, 0] # reversed parity pair
assert sol.countOppositeParity([1, 2, 1, 2, 1]) == [2, 2, 1, 1, 0] # alternating pattern
assert sol.countOppositeParity([2, 1, 2, 1, 2]) == [2, 2, 1, 1, 0] # alternating starting even
assert sol.countOppositeParity([1, 1, 1, 2]) == [1, 1, 1, 0] # only one opposite parity at end
assert sol.countOppositeParity([2, 2, 2, 1]) == [1, 1, 1, 0] # single odd at end
assert sol.countOppositeParity([1, 4, 6, 8, 3]) == [3, 1, 1, 1, 0] # mixed distribution
Test Summary
| Test | Why |
|---|---|
[1, 2, 3, 4] |
Validates the primary example |
[1] |
Smallest allowed input |
[2, 4, 6, 8] |
All even numbers |
[1, 3, 5, 7] |
All odd numbers |
[1, 2] |
Smallest non-trivial opposite parity case |
[2, 1] |
Opposite parity with reversed ordering |
[1, 2, 1, 2, 1] |
Alternating parity pattern |
[2, 1, 2, 1, 2] |
Alternating pattern starting with even |
[1, 1, 1, 2] |
Single opposite-parity element at the end |
[2, 2, 2, 1] |
Single odd element at the end |
[1, 4, 6, 8, 3] |
General mixed case |
Edge Cases
Single Element Array
When the array contains only one element, there are no indices to the right. Therefore, the score must be zero. A common mistake is assuming every index has at least one later element. The algorithm naturally handles this because both counters start at zero, so the lone element receives a score of zero.
All Numbers Have The Same Parity
If every element is even, or every element is odd, no valid opposite-parity pairs exist. Every answer should therefore be zero. The algorithm handles this correctly because the counter representing the opposite parity never increases, so every score remains zero.
Opposite Parity Appears Only Near The End
Consider an input such as [1, 1, 1, 2]. Every odd number should count the single even number at the end. Implementations that scan in the wrong direction or update counts before computing the current answer can easily introduce off-by-one errors. By computing the answer first and then updating the counters, the algorithm ensures only elements strictly to the right are counted.
Alternating Parity Arrays
Arrays such as [1, 2, 1, 2, 1] contain many valid opposite-parity pairs. These cases verify that the counters correctly accumulate all future elements of the opposite parity. Since the algorithm maintains exact suffix counts at every step, it correctly computes all scores without repeatedly scanning the remainder of the array.