Problem Walkthrough

Longest Turbulent Subarray LeetCode 978

Track two counters for subarray length ending with an increase or decrease. When the comparison alternates, extend the opposite counter; when equal, reset both. O(n) time, O(1) space.

7 min read|

Longest Turbulent Subarray

LeetCode 978

Problem Overview

LeetCode 978 — Longest Turbulent Subarray — gives you an integer array arr. A subarray is turbulent if the comparison sign alternates between each pair of adjacent elements. Specifically, for a subarray arr[i..j], the signs of arr[i]-arr[i+1], arr[i+1]-arr[i+2], etc. must alternate between positive and negative.

For example, [9, 4, 2, 10, 7, 8, 8, 1, 9] has a longest turbulent subarray of length 5: [4, 2, 10, 7, 8] where the comparisons are >, <, >, < — perfectly alternating. Equal adjacent elements break any turbulent run.

This is a linear scan problem that can be solved with two counters or a sliding window. The two-counter approach is the most elegant: track the length of the longest turbulent subarray ending at each position with the last comparison being up versus down.

  • Input: integer array arr
  • Turbulent: adjacent comparisons alternate between > and <
  • Equal adjacent elements break turbulence
  • Return the length of the longest turbulent subarray
  • A single element has turbulent length 1

The Two-Counter Approach

Define inc as the length of the longest turbulent subarray ending at the current position where the last step was an increase (arr[i] > arr[i-1]). Define dec similarly for a decrease. Initialize both to 1.

For each position i from 1 to n-1, compare arr[i] with arr[i-1]. If arr[i] > arr[i-1], the last step is an increase: inc = dec + 1 (extending a subarray that ended with a decrease) and dec = 1 (reset). If arr[i] < arr[i-1], the last step is a decrease: dec = inc + 1 and inc = 1.

If arr[i] == arr[i-1], both counters reset to 1 because equal elements cannot be part of a turbulent subarray. Track the maximum of inc and dec across all positions. This single pass gives the answer in O(n) time.

💡

Why dec+1 and inc+1?

When arr[i] > arr[i-1] (increase), the previous step must have been a decrease for turbulence. So inc extends from dec. Conversely for a decrease. This cross-referencing is what enforces the alternating pattern.

Step-by-Step Walkthrough

Consider arr = [9, 4, 2, 10, 7, 8, 8, 1, 9]. Start: inc=1, dec=1, maxLen=1. i=1: 4<9 (decrease), dec=inc+1=2, inc=1. max=2. i=2: 2<4 (decrease), dec=inc+1=2, inc=1. max=2. Note: two consecutive decreases do not extend turbulence.

i=3: 10>2 (increase), inc=dec+1=3, dec=1. max=3. i=4: 7<10 (decrease), dec=inc+1=4, inc=1. max=4. i=5: 8>7 (increase), inc=dec+1=5, dec=1. max=5.

i=6: 8==8 (equal), inc=1, dec=1. max stays 5. i=7: 1<8 (decrease), dec=inc+1=2, inc=1. max=5. i=8: 9>1 (increase), inc=dec+1=3, dec=1. max=5. Answer: 5 (the subarray [4, 2, 10, 7, 8]).

Sliding Window Variant

An alternative approach uses a sliding window with left and right pointers. Expand right while the turbulent condition holds: the comparison between arr[right] and arr[right-1] must be opposite to the comparison between arr[right-1] and arr[right-2].

When the condition breaks — either equal elements or same-direction comparison — move left to right-1 (or right if equal). Track the maximum window length throughout. This variant is equivalent to the two-counter approach but explicitly maintains window boundaries.

The sliding window variant is sometimes easier to extend to related problems. For instance, if the problem asked for the actual turbulent subarray (not just its length), the window boundaries give you the start and end indices directly.

ℹ️

Two Counters vs Sliding Window

The two-counter approach is more concise and uses no extra variables for window boundaries. The sliding window is more visual and easier to debug. Both are O(n) time O(1) space — choose whichever you find clearer under interview pressure.

Implementation in Python and Java

In Python, the two-counter solution is about 12 lines. Initialize inc = dec = result = 1. Loop from 1 to len(arr)-1. Use if/elif/else for the three cases (greater, less, equal). Update result = max(result, inc, dec) each iteration.

In Java, use the same pattern with int inc = 1, dec = 1, result = 1. The comparison logic is identical. Java's ternary operator can make the updates compact but an explicit if-else chain is clearer.

Edge case: if the array has length 1, return 1 immediately. If all elements are equal, the answer is 1. If the array is strictly increasing or decreasing, the answer is 2 (any two adjacent elements form a trivial turbulent subarray of length 2).

Complexity Analysis

Time complexity is O(n) — a single pass through the array with O(1) work per element. No nested loops, no sorting, no data structure operations beyond simple comparisons and assignments.

Space complexity is O(1) — only three integer variables (inc, dec, result) regardless of input size. This is optimal; you cannot solve the problem without reading every element, and you need no auxiliary storage.

This is among the simplest O(n) solutions on LeetCode. The elegance lies in the cross-referencing of inc and dec: each counter builds on the other, naturally enforcing the alternating constraint without explicit bookkeeping.

YeetCode Flashcard Tip

Longest Turbulent Subarray is a great warm-up for alternating-pattern problems. Practice it alongside Wiggle Subsequence and Longest Mountain in Array on YeetCode to build pattern recognition for zigzag structures.

Ready to master algorithm patterns?

YeetCode flashcards help you build pattern recognition through active recall and spaced repetition.

Start practicing now