2760. Longest Even Odd Subarray With Threshold
Problem Description
You are given an integer array nums
(0-indexed) and an integer threshold
. Your task is to find the length of the longest subarray that satisfies all of the following conditions:
-
The subarray must start with an even number: The first element of the subarray (
nums[l]
) must be even, meaningnums[l] % 2 == 0
-
Elements must alternate between even and odd: For any two consecutive elements in the subarray, one must be even and the other must be odd. In other words, for all indices
i
in the range[l, r-1]
, we neednums[i] % 2 != nums[i+1] % 2
-
All elements must not exceed the threshold: Every element in the subarray must be less than or equal to
threshold
. For all indicesi
in the range[l, r]
, we neednums[i] <= threshold
The goal is to return the length of the longest subarray that meets all these requirements. If no such subarray exists, return 0.
For example, if nums = [3, 2, 5, 4]
and threshold = 5
:
- A valid subarray could be
[2, 5, 4]
starting at index 1, which has length 3 - It starts with 2 (even), alternates (2-even, 5-odd, 4-even), and all elements are ≤ 5
The solution approach iterates through each possible starting position l
. When a valid starting position is found (even number ≤ threshold), it extends the subarray as far as possible while maintaining the alternating pattern and threshold constraint, keeping track of the maximum length found.
Intuition
The key insight is that every valid subarray must start with an even number. This gives us a natural starting point - we can check each position in the array to see if it could be the beginning of a valid subarray.
Think about it this way: if we're standing at any position l
in the array and nums[l]
is even and within the threshold, we've found a potential starting point. From here, we want to extend the subarray as far as possible to the right while maintaining the alternating pattern and staying within the threshold.
The alternating pattern means that if we start with an even number, the next must be odd, then even again, and so on. We can check this by comparing nums[r] % 2
with nums[r-1] % 2
- they should always be different for consecutive elements.
Why does this brute force approach work well? Because once we violate any condition while extending from position l
, we can't fix it by extending further. The subarray from l
has reached its maximum possible length. We then move to the next potential starting position and repeat the process.
The beauty of this approach is its simplicity - we're essentially asking: "For each valid starting position, how far can I extend?" We don't need complex dynamic programming or data structures because the constraints are local (each element compared to threshold, consecutive elements compared to each other for parity).
By trying all possible starting positions and finding the maximum length achievable from each, we guarantee finding the overall longest valid subarray. The time complexity of O(n²)
in the worst case is acceptable since we're doing a straightforward scan for each starting position.
Learn more about Sliding Window patterns.
Solution Approach
The implementation uses a straightforward enumeration approach where we check every possible starting position for a valid subarray.
Step-by-step implementation:
-
Initialize variables: We set
ans = 0
to track the maximum length found, andn = len(nums)
for the array size. -
Enumerate all possible starting positions: We iterate through each index
l
from0
ton-1
as a potential starting point. -
Check starting position validity: For each
l
, we verify ifnums[l]
meets our starting conditions:nums[l] % 2 == 0
(must be even)nums[l] <= threshold
(must not exceed threshold)
-
Extend the subarray: If
l
is a valid starting point, we initializer = l + 1
and try to extend the subarray to the right. We continue extending while:r < n
(within array bounds)nums[r] % 2 != nums[r-1] % 2
(maintains alternating pattern)nums[r] <= threshold
(stays within threshold)
-
Update maximum length: Once we can't extend further from position
l
, we calculate the subarray length asr - l
and updateans = max(ans, r - l)
. -
Return result: After checking all possible starting positions, we return
ans
.
Why this works:
The algorithm systematically checks every valid subarray by:
- Starting only at positions with even numbers (condition 1)
- Extending only while alternation is maintained (condition 2)
- Stopping when threshold is exceeded (condition 3)
Since we examine all possible valid subarrays and keep track of the maximum length, we're guaranteed to find the optimal answer. The nested loop structure (outer loop for starting positions, inner while loop for extending) ensures we don't miss any valid subarray.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with nums = [3, 2, 5, 4, 7, 6]
and threshold = 6
.
Starting from index 0 (nums[0] = 3):
- 3 is odd, so it cannot be a valid starting point (must start with even)
- Skip to next position
Starting from index 1 (nums[1] = 2):
- 2 is even ✓ and 2 ≤ 6 ✓
- Valid starting point found, begin extending:
- r = 2: nums[2] = 5, check: 5 ≤ 6 ✓ and 5 % 2 (odd) ≠ 2 % 2 (even) ✓
- r = 3: nums[3] = 4, check: 4 ≤ 6 ✓ and 4 % 2 (even) ≠ 5 % 2 (odd) ✓
- r = 4: nums[4] = 7, check: 7 ≤ 6 ✗ (exceeds threshold)
- Stop extending, subarray length = 3 - 1 = 3
- Update ans = max(0, 3) = 3
Starting from index 2 (nums[2] = 5):
- 5 is odd, skip
Starting from index 3 (nums[3] = 4):
- 4 is even ✓ and 4 ≤ 6 ✓
- Valid starting point, begin extending:
- r = 4: nums[4] = 7, check: 7 ≤ 6 ✗
- Stop extending, subarray length = 4 - 3 = 1
- ans remains 3
Starting from index 4 (nums[4] = 7):
- 7 > 6, exceeds threshold, skip
Starting from index 5 (nums[5] = 6):
- 6 is even ✓ and 6 ≤ 6 ✓
- Valid starting point, but r = 6 is out of bounds
- Subarray length = 6 - 5 = 1
- ans remains 3
Result: The longest valid subarray is [2, 5, 4]
with length 3.
Solution Implementation
1class Solution:
2 def longestAlternatingSubarray(self, nums: List[int], threshold: int) -> int:
3 """
4 Find the longest alternating subarray starting with an even number
5 where all elements are <= threshold.
6
7 Args:
8 nums: List of integers
9 threshold: Maximum allowed value for elements in the subarray
10
11 Returns:
12 Length of the longest valid alternating subarray
13 """
14 max_length = 0
15 n = len(nums)
16
17 # Try each position as a potential starting point
18 for left in range(n):
19 # Valid subarray must start with an even number <= threshold
20 if nums[left] % 2 == 0 and nums[left] <= threshold:
21 # Extend the subarray as far as possible
22 right = left + 1
23
24 # Continue while elements alternate between even/odd and are <= threshold
25 while (right < n and
26 nums[right] % 2 != nums[right - 1] % 2 and
27 nums[right] <= threshold):
28 right += 1
29
30 # Update the maximum length found
31 current_length = right - left
32 max_length = max(max_length, current_length)
33
34 return max_length
35
1class Solution {
2 public int longestAlternatingSubarray(int[] nums, int threshold) {
3 int maxLength = 0;
4 int arrayLength = nums.length;
5
6 // Iterate through each possible starting position
7 for (int left = 0; left < arrayLength; ++left) {
8 // Check if current element can be a valid start:
9 // 1. Must be even (starts with even number)
10 // 2. Must not exceed threshold
11 if (nums[left] % 2 == 0 && nums[left] <= threshold) {
12 // Initialize right pointer to explore the subarray
13 int right = left + 1;
14
15 // Extend the subarray while conditions are met:
16 // 1. Within array bounds
17 // 2. Current and previous elements have different parity (alternating)
18 // 3. Current element doesn't exceed threshold
19 while (right < arrayLength &&
20 nums[right] % 2 != nums[right - 1] % 2 &&
21 nums[right] <= threshold) {
22 ++right;
23 }
24
25 // Update maximum length found so far
26 maxLength = Math.max(maxLength, right - left);
27 }
28 }
29
30 return maxLength;
31 }
32}
33
1class Solution {
2public:
3 int longestAlternatingSubarray(vector<int>& nums, int threshold) {
4 int maxLength = 0;
5 int arraySize = nums.size();
6
7 // Try each position as a potential starting point
8 for (int left = 0; left < arraySize; ++left) {
9 // Check if current position can be a valid start:
10 // 1. Must be even
11 // 2. Must not exceed threshold
12 if (nums[left] % 2 == 0 && nums[left] <= threshold) {
13 // Extend the subarray as far as possible
14 int right = left + 1;
15
16 // Continue extending while:
17 // 1. Within array bounds
18 // 2. Parity alternates (current and previous have different parity)
19 // 3. Current element doesn't exceed threshold
20 while (right < arraySize &&
21 nums[right] % 2 != nums[right - 1] % 2 &&
22 nums[right] <= threshold) {
23 ++right;
24 }
25
26 // Update maximum length found so far
27 maxLength = max(maxLength, right - left);
28 }
29 }
30
31 return maxLength;
32 }
33};
34
1/**
2 * Finds the length of the longest alternating subarray that starts with an even number
3 * and all elements are less than or equal to the threshold.
4 *
5 * @param nums - The input array of numbers
6 * @param threshold - The maximum allowed value for elements in the subarray
7 * @returns The length of the longest valid alternating subarray
8 */
9function longestAlternatingSubarray(nums: number[], threshold: number): number {
10 const arrayLength: number = nums.length;
11 let maxLength: number = 0;
12
13 // Iterate through each possible starting position
14 for (let leftIndex: number = 0; leftIndex < arrayLength; leftIndex++) {
15 // Check if current element can be a valid start:
16 // 1. Must be even
17 // 2. Must be within threshold
18 if (nums[leftIndex] % 2 === 0 && nums[leftIndex] <= threshold) {
19 // Initialize right pointer to explore the alternating pattern
20 let rightIndex: number = leftIndex + 1;
21
22 // Extend the subarray while conditions are met:
23 // 1. Elements alternate between even and odd
24 // 2. Elements are within threshold
25 while (rightIndex < arrayLength &&
26 nums[rightIndex] % 2 !== nums[rightIndex - 1] % 2 &&
27 nums[rightIndex] <= threshold) {
28 rightIndex++;
29 }
30
31 // Update maximum length found so far
32 const currentLength: number = rightIndex - leftIndex;
33 maxLength = Math.max(maxLength, currentLength);
34 }
35 }
36
37 return maxLength;
38}
39
Time and Space Complexity
The time complexity is O(n²)
, where n
is the length of the array nums
.
The algorithm uses a nested loop structure: the outer loop iterates through each index l
from 0
to n-1
, and for each valid starting position (where nums[l] % 2 == 0
and nums[l] <= threshold
), the inner while loop extends the subarray by incrementing r
until the alternating pattern breaks or the threshold is exceeded. In the worst case, for each starting position l
, the inner loop can iterate up to n - l - 1
times. This gives us a total time complexity of O(n) * O(n) = O(n²)
.
The space complexity is O(1)
.
The algorithm only uses a constant amount of extra space for variables ans
, n
, l
, and r
, regardless of the input size. No additional data structures that scale with the input are created.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Forgetting to check threshold condition for the starting element
A common mistake is only checking if nums[left]
is even when determining a valid starting position, but forgetting to also verify nums[left] <= threshold
.
Incorrect code:
# Missing threshold check for starting element if nums[left] % 2 == 0: # Only checking if even right = left + 1 while (right < n and nums[right] % 2 != nums[right - 1] % 2 and nums[right] <= threshold): right += 1
Why this fails: If nums[left]
is even but exceeds the threshold (e.g., nums[left] = 10, threshold = 5
), the subarray violates condition 3 from the start.
Solution: Always check both conditions for the starting element:
if nums[left] % 2 == 0 and nums[left] <= threshold: # Now we can safely start extending
2. Incorrect alternation check using the wrong index
Another pitfall is using the wrong indices when checking the alternation pattern, such as comparing nums[right]
with nums[left]
instead of nums[right - 1]
.
Incorrect code:
while (right < n and nums[right] % 2 != nums[left] % 2 and # Wrong! Comparing with left nums[right] <= threshold): right += 1
Why this fails: This only ensures nums[right]
has different parity from nums[left]
, not that consecutive elements alternate. For example, with [2, 4, 3]
, this would incorrectly accept [2, 4]
as valid since 4 has different parity from 2, even though 2 and 4 are both even.
Solution: Always compare consecutive elements:
while (right < n and nums[right] % 2 != nums[right - 1] % 2 and # Correct adjacency check nums[right] <= threshold): right += 1
3. Off-by-one error when calculating subarray length
Some might incorrectly calculate the length as right - left + 1
after the while loop ends.
Incorrect code:
current_length = right - left + 1 # Wrong! Off by one
max_length = max(max_length, current_length)
Why this fails: When the while loop exits, right
points to the first invalid position (or n
if we reached the end). The valid subarray spans from left
to right - 1
, so the length is right - left
, not right - left + 1
.
Solution: Use the correct formula:
current_length = right - left # Correct length calculation
max_length = max(max_length, current_length)
Given a sorted array of integers and an integer called target, find the element that
equals to the target and return its index. Select the correct code that fills the
___
in the given code snippet.
1def binary_search(arr, target):
2 left, right = 0, len(arr) - 1
3 while left ___ right:
4 mid = (left + right) // 2
5 if arr[mid] == target:
6 return mid
7 if arr[mid] < target:
8 ___ = mid + 1
9 else:
10 ___ = mid - 1
11 return -1
12
1public static int binarySearch(int[] arr, int target) {
2 int left = 0;
3 int right = arr.length - 1;
4
5 while (left ___ right) {
6 int mid = left + (right - left) / 2;
7 if (arr[mid] == target) return mid;
8 if (arr[mid] < target) {
9 ___ = mid + 1;
10 } else {
11 ___ = mid - 1;
12 }
13 }
14 return -1;
15}
16
1function binarySearch(arr, target) {
2 let left = 0;
3 let right = arr.length - 1;
4
5 while (left ___ right) {
6 let mid = left + Math.trunc((right - left) / 2);
7 if (arr[mid] == target) return mid;
8 if (arr[mid] < target) {
9 ___ = mid + 1;
10 } else {
11 ___ = mid - 1;
12 }
13 }
14 return -1;
15}
16
Recommended Readings
https assets algo monster cover_photos stack svg Sliding Window Maximum Monotonic Stack We have an array and a sliding window defined by a start index and an end index The sliding window moves from left of the array to right There are always k elements in the window The window
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
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!