162. Find Peak Element - Explanation
Description
A peak element is an element that is strictly greater than its neighbors.
You are given a 0-indexed integer array nums, find a peak element, and return its index. If the array contains multiple peaks, return the index to any of the peaks.
You may imagine that nums[-1] = nums[n] = -∞. In other words, an element is always considered to be strictly greater than a neighbor that is outside the array.
You must write an algorithm that runs in O(log n) time.
Example 1:
Input: nums = [1,2,3,1]
Output: 2Explanation: 3 is a peak element and your function should return the index number 2.
Example 2:
Input: nums = [1,2,1,3,4,5,0]
Output: 5Explanation: 5 is a peak element and your function should return the index number 5.
Constraints:
1 <= nums.length <= 1000.-(2^31) <= nums[i] <= ((2^31)-1)nums[i] != nums[i + 1]for all validi.
Topics
Prerequisites
Before attempting this problem, you should be comfortable with:
- Binary Search - The optimal solution uses binary search on an unsorted array by comparing neighbors to determine which half contains a peak
- Array Neighbor Comparison - Understanding how to safely compare elements with their neighbors while handling boundary conditions
1. Brute Force
Intuition
A peak element is greater than its neighbors. Since adjacent elements are guaranteed to be different and elements outside the array are treated as negative infinity, we can scan from left to right. The first time we find an element greater than its next neighbor, we have found a peak. If no such element exists before the last index, the last element itself must be a peak (since the array keeps increasing).
Algorithm
- Iterate through the array from index
0ton-2. - If the current element is greater than the next element, return the current index as a peak.
- If the loop completes without finding a peak, return
n-1(the last element is the peak).
Time & Space Complexity
- Time complexity:
- Space complexity:
2. Binary Search
Intuition
Binary search works here because a peak must exist in any subarray. At each midpoint, if the element is smaller than its left neighbor, a peak exists on the left side. If it is smaller than its right neighbor, a peak exists on the right side. Otherwise, the midpoint itself is a peak. This property allows us to eliminate half the search space each iteration.
Algorithm
- Initialize two pointers
l = 0andr = n - 1. - While
l <= r:- Compute the midpoint
m. - If
m > 0andnums[m] < nums[m - 1], move the right pointer tom - 1. - Else if
m < n - 1andnums[m] < nums[m + 1], move the left pointer tom + 1. - Otherwise,
mis a peak; returnm.
- Compute the midpoint
- Return the result.
Time & Space Complexity
- Time complexity:
- Space complexity:
3. Recursive Binary Search
Intuition
This is the same binary search logic implemented recursively. At each step, we compare the middle element with its right neighbor. If the middle is greater, a peak lies in the left half (including mid). Otherwise, a peak lies in the right half. The recursion continues until the search range narrows to a single element, which must be a peak.
Algorithm
- Define a recursive function
binary_search(l, r). - Base case: If
l == r, returnlas the peak. - Compute the midpoint
m. - If
nums[m] > nums[m + 1], recurse on the left half:binary_search(l, m). - Otherwise, recurse on the right half:
binary_search(m + 1, r). - Start the recursion with
binary_search(0, n - 1).
Time & Space Complexity
- Time complexity:
- Space complexity: for recursion stack.
4. Binary Search (Optimal)
Intuition
We can simplify the binary search by using l < r as the loop condition instead of l <= r. This eliminates extra boundary checks. By always comparing mid with mid + 1, we ensure we move toward a peak. When l == r, we have found the peak without needing additional checks.
Algorithm
- Initialize
l = 0andr = n - 1. - While
l < r:- Compute
m = (l + r) / 2. - If
nums[m] > nums[m + 1], the peak is atmor to the left, so setr = m. - Otherwise, the peak is to the right, so set
l = m + 1.
- Compute
- When the loop exits,
lpoints to a peak. Returnl.
Time & Space Complexity
- Time complexity:
- Space complexity:
Common Pitfalls
Incorrect Boundary Handling
When accessing nums[m-1] or nums[m+1], you must check that m > 0 or m < n-1 respectively to avoid array index out of bounds errors. Elements outside the array are conceptually negative infinity, so boundary elements can be peaks if they are greater than their single neighbor.
Using Wrong Loop Condition
Using l <= r versus l < r changes the termination logic significantly. With l < r, when the loop exits, l and r converge to the peak index. With l <= r, you need explicit return statements inside the loop. Mixing these approaches incorrectly leads to infinite loops or missed peaks.
Misunderstanding the Peak Guarantee
The problem guarantees that a peak always exists because adjacent elements are distinct and boundaries are treated as negative infinity. Some solutions incorrectly return -1 or handle the "no peak found" case, which is unnecessary. Understanding why a peak must exist (the array cannot be strictly increasing forever due to the right boundary) helps avoid overcomplicating the solution.
Sign in to join the discussion