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 valid i.Before attempting this problem, you should be comfortable with:
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).
0 to n-2.n-1 (the last element is the peak).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.
l = 0 and r = n - 1.l <= r:m.m > 0 and nums[m] < nums[m - 1], move the right pointer to m - 1.m < n - 1 and nums[m] < nums[m + 1], move the left pointer to m + 1.m is a peak; return m.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.
binary_search(l, r).l == r, return l as the peak.m.nums[m] > nums[m + 1], recurse on the left half: binary_search(l, m).binary_search(m + 1, r).binary_search(0, n - 1).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.
l = 0 and r = n - 1.l < r:m = (l + r) / 2.nums[m] > nums[m + 1], the peak is at m or to the left, so set r = m.l = m + 1.l points to a peak. Return l.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 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.
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.