LeetCode 2765 - Longest Alternating Subarray
This problem asks us to find the longest contiguous subarray that follows a very specific alternating pattern. Given an integer array nums, we need to identify subarrays where: 1. The subarray length is at least 2. 2.
Difficulty: 🟢 Easy
Topics: Array, Enumeration
Solution
LeetCode 2765 - Longest Alternating Subarray
Problem Understanding
This problem asks us to find the longest contiguous subarray that follows a very specific alternating pattern.
Given an integer array nums, we need to identify subarrays where:
- The subarray length is at least
2. - The second element is exactly one greater than the first element.
- Every subsequent difference alternates between
-1and+1.
If a valid alternating subarray starts with values [x, x + 1], then every following element must continue the pattern:
x, x+1, x, x+1, x, x+1, ...
For example:
[3, 4, 3, 4, 3]
is valid because the consecutive differences are:
+1, -1, +1, -1
However:
[3, 4, 5]
is not valid because the differences are:
+1, +1
which does not alternate.
The input consists of an array nums with length between 2 and 100. Since the array is quite small, even quadratic solutions are acceptable. The values themselves range up to 10^4, but the actual magnitude of the numbers is not important. What matters is the relationship between neighboring elements.
The output should be the length of the longest valid alternating subarray. If no alternating subarray exists, we return -1.
Several edge cases are important:
- Arrays where no adjacent pair differs by exactly
1. - Arrays containing multiple valid alternating subarrays.
- Arrays where a valid alternating sequence begins in the middle.
- Arrays where the longest valid subarray has length exactly
2. - Arrays where an alternating pattern breaks after several elements.
Because the array length is only 100, we can afford to examine every possible starting position and extend the alternating sequence as far as possible.
Approaches
Brute Force
The most direct solution is to examine every possible subarray.
For each starting index i, we can generate every ending index j > i and verify whether the subarray nums[i:j+1] satisfies the alternating conditions.
To validate a subarray, we must check:
- The first difference equals
+1. - Every later difference alternates between
-1and+1.
Since there are O(n²) subarrays and each validation may require O(n) work, the total complexity becomes O(n³).
This approach is straightforward and obviously correct because it explicitly checks every candidate subarray. However, it performs unnecessary repeated work when verifying overlapping subarrays.
Optimal Enumeration
Instead of generating every subarray, we can treat each index as a potential starting point.
A valid alternating subarray must begin with:
nums[i+1] = nums[i] + 1
If this condition is not satisfied, index i cannot start a valid alternating sequence.
Once we find a valid start, we extend the sequence to the right while tracking the expected difference. After the initial +1, the next difference must be -1, then +1, then -1, and so on.
As soon as a difference does not match the expected value, the alternating sequence ends.
This avoids repeatedly validating the same prefix and reduces the complexity to O(n²).
Comparison of Approaches
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n³) | O(1) | Checks every subarray and validates each one independently |
| Optimal | O(n²) | O(1) | Extends alternating sequences from each starting position |
Algorithm Walkthrough
Optimal Algorithm
- Initialize the answer as
-1. This represents the case where no valid alternating subarray exists. - Iterate through every index
ifrom0ton - 2. Each index is considered as a possible starting position. - Check whether
nums[i + 1] == nums[i] + 1. If not, no valid alternating subarray can start ati, so move to the next index. - If the condition is satisfied, we already have a valid alternating subarray of length
2. Update the answer accordingly. - Set the current length to
2. - The next required difference is
-1, because the first difference was already+1. - Continue extending the subarray using index
jstarting fromi + 2. - For each position, compute:
nums[j] - nums[j - 1]
- If this difference equals the currently expected value, extend the alternating sequence:
- Increase the current length.
- Update the answer.
- Flip the expected difference by multiplying it by
-1.
- If the difference does not match the expected value, stop extending from this starting index.
- After processing all starting positions, return the answer.
Why it works
For every possible starting index, the algorithm checks exactly the longest alternating subarray beginning at that position. Any valid alternating subarray must have some starting index, and when that starting index is examined, the algorithm extends the sequence until the first violation occurs. Therefore every valid alternating subarray is considered, and the maximum length among them is recorded. Since the algorithm never accepts a sequence that violates the required alternating differences, the final answer is correct.
Python Solution
from typing import List
class Solution:
def alternatingSubarray(self, nums: List[int]) -> int:
n = len(nums)
answer = -1
for start in range(n - 1):
if nums[start + 1] != nums[start] + 1:
continue
current_length = 2
answer = max(answer, current_length)
expected_diff = -1
for end in range(start + 2, n):
if nums[end] - nums[end - 1] == expected_diff:
current_length += 1
answer = max(answer, current_length)
expected_diff *= -1
else:
break
return answer
The implementation begins by storing the array length and initializing the answer to -1.
The outer loop examines every index as a potential starting position. A valid alternating subarray must begin with a difference of exactly +1, so positions that fail this requirement are skipped immediately.
When a valid start is found, a length-2 alternating subarray already exists. The algorithm records this and initializes the next expected difference to -1.
The inner loop attempts to extend the alternating sequence. Each new difference is compared against the expected value. If it matches, the subarray length increases, the answer is updated, and the expected difference is flipped. If it does not match, the current alternating sequence cannot continue, so the loop stops.
After all starting positions are processed, the maximum length found is returned.
Go Solution
func alternatingSubarray(nums []int) int {
n := len(nums)
answer := -1
for start := 0; start < n-1; start++ {
if nums[start+1] != nums[start]+1 {
continue
}
currentLength := 2
if currentLength > answer {
answer = currentLength
}
expectedDiff := -1
for end := start + 2; end < n; end++ {
if nums[end]-nums[end-1] == expectedDiff {
currentLength++
if currentLength > answer {
answer = currentLength
}
expectedDiff *= -1
} else {
break
}
}
}
return answer
}
The Go implementation follows exactly the same logic as the Python version. Since the constraints are very small, standard integer arithmetic is completely safe and there is no risk of overflow. Go slices provide efficient indexed access, so no additional data structures are required.
Worked Examples
Example 1
nums = [2,3,4,3,4]
Start = 0
Initial pair:
2 -> 3
difference = +1
Valid start.
| Step | Current Element | Difference | Expected | Length |
|---|---|---|---|---|
| Start | 3 | +1 | +1 | 2 |
| End=2 | 4 | +1 | -1 | Stop |
Current best:
answer = 2
Start = 1
Initial pair:
3 -> 4
difference = +1
Valid start.
| Step | Current Element | Difference | Expected | Length |
|---|---|---|---|---|
| Start | 4 | +1 | +1 | 2 |
| End=3 | 3 | -1 | -1 | 3 |
| End=4 | 4 | +1 | +1 | 4 |
Current best:
answer = 4
Start = 2
Initial pair:
4 -> 3
difference = -1
Invalid start.
Start = 3
Initial pair:
3 -> 4
difference = +1
Valid start.
Length is only:
2
Final answer:
4
Example 2
nums = [4,5,6]
Start = 0
4 -> 5
Valid start.
Next difference:
6 - 5 = 1
Expected:
-1
Mismatch, stop.
Length:
2
Start = 1
5 -> 6
Valid start.
Length:
2
Final answer:
2
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n²) | For each starting index, we may extend through the remaining array |
| Space | O(1) | Only a few variables are maintained |
The outer loop runs n times. In the worst case, each starting position may scan much of the remaining array, resulting in O(n²) time. No auxiliary data structures proportional to the input size are used, so the space complexity remains constant.
Test Cases
from typing import List
s = Solution()
assert s.alternatingSubarray([2, 3, 4, 3, 4]) == 4 # example 1
assert s.alternatingSubarray([4, 5, 6]) == 2 # example 2
assert s.alternatingSubarray([1, 2]) == 2 # smallest valid array
assert s.alternatingSubarray([2, 2]) == -1 # no valid start
assert s.alternatingSubarray([5, 4]) == -1 # difference is not +1
assert s.alternatingSubarray([1, 2, 1]) == 3 # exact alternating length 3
assert s.alternatingSubarray([1, 2, 1, 2]) == 4 # exact alternating length 4
assert s.alternatingSubarray([1, 2, 1, 2, 1]) == 5 # entire array valid
assert s.alternatingSubarray([1, 2, 3, 2, 3]) == 4 # longest starts later
assert s.alternatingSubarray([3, 4, 3, 4, 5]) == 4 # breaks at end
assert s.alternatingSubarray([10, 11, 10, 11, 10, 11]) == 6 # long alternating sequence
assert s.alternatingSubarray([7, 8, 7, 8, 9, 8]) == 4 # pattern breaks in middle
assert s.alternatingSubarray([1, 3, 5, 7]) == -1 # no adjacent +1 pair
assert s.alternatingSubarray([5, 6, 5, 6, 5, 6, 5]) == 7 # maximum covers entire array
Test Summary
| Test | Why |
|---|---|
[2,3,4,3,4] |
Official example with longest length 4 |
[4,5,6] |
Official example with answer 2 |
[1,2] |
Smallest valid input |
[2,2] |
No valid alternating subarray |
[5,4] |
Adjacent difference is negative |
[1,2,1] |
Alternating sequence of length 3 |
[1,2,1,2] |
Alternating sequence of length 4 |
[1,2,1,2,1] |
Entire array alternates |
[1,2,3,2,3] |
Longest subarray begins after index 0 |
[3,4,3,4,5] |
Alternation breaks near the end |
[10,11,10,11,10,11] |
Long valid sequence |
[7,8,7,8,9,8] |
Pattern interruption in the middle |
[1,3,5,7] |
No valid starting pair exists |
[5,6,5,6,5,6,5] |
Entire array forms one alternating subarray |
Edge Cases
No Valid Starting Pair
Consider:
[1, 3, 5, 7]
Every valid alternating subarray must begin with a difference of exactly +1. Since no adjacent pair satisfies this condition, the answer should be -1. A common bug is accidentally returning 0 or 1. The implementation avoids this by initializing the answer to -1 and only updating it after finding a valid start.
Valid Subarray of Length Two Only
Consider:
[4, 5, 6]
The pair [4,5] is valid, but extending it fails because the next difference is +1 instead of -1. The implementation immediately records length 2 once a valid start is found, ensuring these cases are handled correctly.
Alternation Breaks After Several Elements
Consider:
[1, 2, 1, 2, 3]
The sequence alternates correctly until the final step. The difference from 2 to 3 is +1, but the expected difference is -1. The inner loop stops exactly when the pattern is violated, preserving the longest valid length found so far.
Longest Subarray Does Not Start at Index Zero
Consider:
[5, 5, 3, 4, 3, 4]
A solution that only examines sequences beginning at the first element would miss the correct answer. The algorithm explicitly checks every possible starting position, guaranteeing that alternating subarrays located anywhere in the array are considered.
Entire Array Is Alternating
Consider:
[8, 9, 8, 9, 8, 9]
The alternating pattern never breaks. The inner loop successfully extends to the end of the array, producing the full array length as the answer. This verifies that the implementation correctly handles the maximum possible extension from a starting position.