Skip to content
← All posts

Valid Mountain Array: Linear Scan

5 min read
leetcodeproblemeasyarrays

Given an array of integers arr, return true if and only if it is a valid mountain array. An array is a mountain if it has at least three elements, there exists some index i with 0 < i < arr.length - 1 such that the values strictly increase from arr[0] to arr[i], and then strictly decrease from arr[i] to arr[arr.length - 1].

This is LeetCode 941: Valid Mountain Array. The problem is asking you to verify a specific shape: values go up, hit a peak, then come back down. No plateaus, no flat spots, and the peak cannot be at the very start or end.

Valid mountain: strictly up, then strictly down03542ascendingpeakdescending0i=03i=15i=24i=32i=4
Array [0, 3, 5, 4, 2] forms a valid mountain. Values strictly increase to 5, then strictly decrease.

Why brute force is overkill

You could try checking every possible peak index and verifying that the left side is strictly increasing and the right side is strictly decreasing. That works, but it is more complex than necessary. A simpler mental model is to walk through the array from left to right in two phases: first climbing up, then climbing down.

The approach: climb up, then climb down

Think of yourself walking along the array from the left:

  1. Climb up while consecutive values are strictly increasing. Keep moving the pointer i forward as long as arr[i] < arr[i + 1].
  2. Check the peak. If i is still at 0, you never climbed up at all, so the array has no ascending portion. If i is at the last index, the array only goes up and never comes back down. Either case means it is not a mountain.
  3. Climb down while consecutive values are strictly decreasing. Keep moving i forward as long as arr[i] > arr[i + 1].
  4. Check the end. If i reached the last index, you successfully climbed all the way down. The array is a valid mountain.

That is the entire algorithm. One pointer, one pass, no extra data structures.

Python solution

def validMountainArray(arr):
    n = len(arr)
    if n < 3:
        return False

    i = 0

    while i + 1 < n and arr[i] < arr[i + 1]:
        i += 1

    if i == 0 or i == n - 1:
        return False

    while i + 1 < n and arr[i] > arr[i + 1]:
        i += 1

    return i == n - 1

The variable i walks forward through the array twice. The first while loop handles the ascending phase, and the second handles the descending phase. If i reaches the end after both phases, the array is a valid mountain.

Let's trace through the example step by step.

Step 1: Check length. Array must have at least 3 elements.

arr03542

Length is 5, which is at least 3. We can proceed.

Step 2: Walk up from the left while strictly increasing.

arr03542

i starts at 0. arr[0]=0 < arr[1]=3, so i becomes 1. arr[1]=3 < arr[2]=5, so i becomes 2. arr[2]=5 is not less than arr[3]=4, so we stop. i = 2.

Step 3: Verify the peak is not at the start or end.

arr03542

i = 2, which is not 0 and not 4 (last index). The peak is in the middle. Good.

Step 4: Walk down from the peak while strictly decreasing.

arr03542

From i=2: arr[2]=5 > arr[3]=4, so i becomes 3. arr[3]=4 > arr[4]=2, so i becomes 4. We reached the last index.

Step 5: Check if we reached the end.

resulttrue

i = 4, which equals len(arr) - 1. We climbed all the way down to the end. This is a valid mountain array.

Why the boundary checks matter

The two checks i == 0 and i == n - 1 after the ascending phase are critical:

  • If i == 0, the first element is not less than the second. That means there is no ascending portion at all. An array like [5, 4, 3, 2, 1] would fail here.
  • If i == n - 1, every consecutive pair was strictly increasing, so the pointer walked all the way to the end. An array like [1, 2, 3, 4, 5] would fail here.

Both cases disqualify the array because a mountain needs both a proper uphill and a proper downhill.

The same pointer i is used for both phases. After climbing up, i is sitting at the peak. Then climbing down starts from that same position. This avoids the need to find the peak separately.

Complexity analysis

ApproachTimeSpace
Linear scan (climb up, climb down)O(n)O(1)

Each element is visited at most once across the two while loops. The pointer only moves forward, so the total work is linear. No extra space is needed beyond the index variable.

The building blocks

Linear scan with phases

This problem demonstrates a clean pattern: scanning an array in distinct phases with a single pointer. Instead of maintaining complex state or checking conditions globally, you break the traversal into stages. Each stage has a simple loop condition, and the transitions between stages handle the validation. This same idea appears in problems where you need to verify that an array follows some structural rule (sorted, bitonic, alternating).

Boundary validation

Checking that the peak is not at the first or last index is a common boundary check. Many array problems require you to verify that some feature does not occur at the edges. Getting these checks right often makes the difference between a correct and an almost-correct solution.

Edge cases

  • Array length less than 3. Return false immediately. A mountain needs at least three elements: one going up, a peak, and one going down.
  • Strictly increasing only. For example, [1, 2, 3, 4]. The ascending phase walks i to the last index, and the check i == n - 1 catches this.
  • Strictly decreasing only. For example, [4, 3, 2, 1]. The ascending phase does not move i at all, and the check i == 0 catches this.
  • Plateau at the peak. For example, [1, 3, 3, 2]. The ascending phase stops when arr[i] is not strictly less than arr[i + 1] (at the first 3). Then i is at index 1. The descending phase checks for strict decrease: arr[1] = 3 is not strictly greater than arr[2] = 3, so the descending loop does not start. i stays at 1, which is not n - 1, so we return false.
  • All equal elements. For example, [3, 3, 3]. The ascending phase does not advance i at all, and i == 0 returns false.

From understanding to recall

The valid mountain array problem has a deceptively simple solution. You might remember "walk up then walk down" but forget the boundary checks that catch edge cases. Or you might second-guess whether the comparisons should be strict or non-strict (they must be strict).

Spaced repetition helps you internalize these details. You write the solution, test it against the edge cases, and then revisit it days later. After a few reps, the two-phase scan with boundary checks becomes second nature. The anchor to hold onto: one pointer, two loops, two boundary checks.

CodeBricks builds review schedules around problems like this so you practice the exact details that tend to fade. Each drill reinforces the pattern until writing it from memory feels effortless.

Related posts