Level Up Your Coding Skills & Crack Interviews — Save up to 50% or more on Educative.io Today! Claim Discount

Arrow
Table of contents

162. Find Peak Element

The Find Peak Element problem is a classic introduction to using binary search beyond sorted arrays. It’s a favorite in interviews because it demonstrates how a simple neighbor check can reveal which half of the current search window must contain a peak while meeting the strict O(logn)O(log n)O(logn) requirement.

Problem statement

You’re given an integer array nums where adjacent values are guaranteed to be different. A peak is an index i such that nums[i] is strictly greater than its immediate neighbors (treat values outside the array as negative infinity). Your task is to find and return the index of any peak.

This is trickier than it first appears because there can be multiple peaks, and a straightforward scan is insufficient when you’re required to complete in logarithmic time.

Constraints:

  • 1 ≤ nums.length ≤ 1000
  • −231nums[i] ≤ 231−1
  • nums[i] != nums[i + 1] for all valid i.

Examples

InputOutputExplanation
[4, 7, 3, 2, 6, 1]1Index 1 is a peak because 7 > 4 and 7 > 3. (Another peak also exists at index 4.)
[1, 2, 5, 4, 3]2Index 2 is a peak because 5 > 2 and 5 > 4.
[9, 2, 6, 1, 3]0Index 0 is a peak because 9 > 2, and the left neighbor is -∞, so it still qualifies. (Another peak also exists at index 2.)

Naive approach

A straightforward approach is to check each index and see whether it’s greater than its neighbors. That works, but it takes linear time $O(n)$ because you may examine every element. Since the problem requires a logarithmic-time solution, scanning the full array is not acceptable.

Optimal solution using Binary Search

To improve upon the linear time complexity of a straightforward scan, we need a different approach to determine where a peak must exist. Instead of checking every index, we take advantage of the fact that adjacent elements are different, so between any two neighbors, the array is always either going up or down. That provides us with a reliable signal at any index, indicating which side can still contain a valid peak, thereby allowing us to quickly shrink the search space.

The core idea is to use binary search using a quick comparison between adjacent elements. At a midpoint mid, we compare nums[mid] with its immediate element to the right, i.e., nums[mid+1] to see which direction the array is moving at that spot. If this element is less than the element to the right, the array is going up from mid to mid + 1, which means we’re heading toward higher values—so a peak must exist somewhere in the right half (mid + 1 .. right). Otherwise (nums[mid] > nums[mid + 1]), the array goes down from mid to mid + 1, so a peak must be on the left half (left .. mid), possibly at mid itself. Repeating this decision keeps halving the range until only one index remains, which is necessarily a peak, giving us an O(log n) solution without scanning the entire array.

Algorithmic Steps

This algorithm is implemented as follows:

  1. Initialize two variables: left = 0 and right = len(nums) - 1.
  2. While left is less than right:
    1. Compute the middle index mid by taking the floor of the average of left and right.
    2. If nums[mid] < nums[mid + 1],
      1. Set left to mid + 1.
    3. Otherwise,
      1. Set right to mid.
  3. When the loop ends, return left (which equals right) as a peak index.

To better understand the solution, let’s walk through the algorithm using the illustration below:

1 / 6

Executable Python implementation

The code below implements the algorithm described above.

Time complexity

The time complexity of this solution is O(log⁡n) because each loop iteration discards roughly half of the remaining search interval, and the loop continues until the interval collapses to a single index.

Space complexity

The space complexity is O(1)) because the algorithm uses only a constant amount of extra memory (a few pointers), regardless of the input size.

Common pitfalls to avoid

  • Using mid - 1 and mid + 1 checks everywhere and going out of bounds: This solution avoids that by only comparing nums[mid] with nums[mid + 1], which is safe as long as mid < right.
  • Writing right = mid - 1 in the decreasing-slope case: That can skip over a valid peak at mid. The correct move is right = mid because mid itself may be the peak.
  • Assuming the array is “mountain-shaped”: The array can have multiple rises and falls. The slope-based binary search still works because it only needs a local slope direction to guarantee a peak exists in that half.
  • Trying to compare both neighbors always: You don’t need to check mid-1 explicitly; comparing mid with mid+1 is enough to decide which side must contain a peak.

Frequently Asked Questions

Why is there guaranteed to be a peak?

Because with edge values treated as -∞, and adjacent values unequal, the sequence must eventually stop increasing, creating a peak somewhere.

Can we return any peak, or must it be the highest?

Any peak is valid. The binary-search approach naturally returns one of them.

What if the array is strictly increasing or strictly decreasing?

Strictly increasing means the last index is a peak. Strictly decreasing means the first index is a peak.

Share with others:

Leave a Reply

Your email address will not be published. Required fields are marked *