The Find Peak Element problem (LeetCode 162 and GeeksforGeeks Peak Element) is an algorithmic classic that challenges standard assumptions about binary search. While software engineers are accustomed to applying binary search exclusively to monotonically sorted sequences, this problem demonstrates how logarithmic division ($O(\log n)$) can be applied to completely unsorted collections by identifying a guaranteed directional gradient. Given an integer array nums where adjacent elements are never equal (nums[i] ≠ nums[i+1]), an element is defined as a peak if it is strictly greater than its immediate neighbors. Crucially, the array is bounded by virtual negative infinity boundaries: nums[-1] = nums[n] = -∞. Below is an exhaustive algorithmic breakdown, mathematical proof of logarithmic convergence, asymptotic analysis, and verified production implementations in C++20, TypeScript, and Python 3.
1. Problem Formalization & Boundary Conditions
Let $A = [a_0, a_1, \dots, a_{n-1}]$ be an array of $n$ distinct adjacent integers. An index $i \in \{0, \dots, n-1\}$ is a peak element if and only if:
- $a_i > a_{i-1}$ (where $a_{-1} = -\infty$)
- $a_i > a_{i+1}$ (where $a_n = -\infty$)
These boundary conditions produce two vital structural consequences:
- Boundary Peaks: The first element $a_0$ is a valid peak if $a_0 > a_1$. Similarly, the final element $a_{n-1}$ is a valid peak if $a_{n-1} > a_{n-2}$. In a single-element array ($n = 1$), index
0is always a valid peak because both virtual neighbors are $-\infty$. - Guaranteed Existence: Because adjacent values are never equal and both boundaries drop to $-\infty$, the sequence cannot be infinitely flat. By the discrete extreme value theorem on finite sequences, every valid input array is guaranteed to contain at least one local peak element.
2. Binary Search Convergence Proof on Unsorted Arrays
The naive approach is a linear scan comparing each element to its neighbors, requiring $O(n)$ time. However, the strict problem constraint demands an $O(\log n)$ runtime. How can binary search function without sorted data?
The key insight lies in local slope invariant preservation. Consider the midpoint index mid and its adjacent right neighbor mid + 1:
- Case 1: Ascending Slope (
nums[mid] < nums[mid + 1]): The array is currently rising towards the right. Since the far right boundary drops off to $-\infty$ at index $n$, the sequence cannot increase indefinitely. It must either continue rising until reaching the boundary element $a_{n-1}$ (making $a_{n-1}$ a peak) or drop at some intermediate point (creating an internal peak). Therefore, a peak is mathematically guaranteed to exist in the right subarray $[mid + 1, \text{right}]$. We discard the left half:left = mid + 1. - Case 2: Descending Slope (
nums[mid] > nums[mid + 1]): The array is falling towards the right. This means indexmiditself could be a peak (if it is also greater thanmid - 1), or an upward peak occurred earlier to the left. Since the far left boundary drops to $-\infty$ at index $-1$, a peak is guaranteed to exist in the left subarray $[\text{left}, mid]$. We discard the right half:right = mid.
Figure 1: Binary search gradient descent/ascent on arbitrary peaks. If nums[mid] < nums[mid+1], a peak must lie to the right.
3. Production Multi-Language Implementations
Here are production-grade implementations demonstrating clean loop termination, integer overflow protection during midpoint calculation, and strict typing.
C++20 Implementation
#include <vector>
#include <cstddef>
class Solution {
public:
int findPeakElement(const std::vector<int>& nums) {
int left = 0;
int right = static_cast<int>(nums.size()) - 1;
// Invariant: Peak is guaranteed within [left, right]
while (left < right) {
// Prevent integer overflow: left + (right - left) / 2
int mid = left + (right - left) / 2;
if (nums[mid] < nums[mid + 1]) {
// Ascending slope: peak must be to the right
left = mid + 1;
} else {
// Descending slope: mid itself or an element to the left is peak
right = mid;
}
}
// Loop terminates when left == right, pointing directly at a peak index
return left;
}
};
TypeScript Implementation
/**
* Finds the index of any local peak element in O(log n) time.
* @param nums - Array of integers where nums[i] !== nums[i+1]
* @returns Index of a confirmed peak element
*/
export function findPeakElement(nums: number[]): number {
let left = 0;
let right = nums.length - 1;
while (left < right) {
const mid = Math.floor(left + (right - left) / 2);
if (nums[mid] < nums[mid + 1]) {
// Ascending gradient: move search space to right sub-interval
left = mid + 1;
} else {
// Descending gradient: peak lies at mid or to the left
right = mid;
}
}
return left;
}
Python 3 Implementation
from typing import List
class Solution:
def findPeakElement(self, nums: List[int]) -> int:
left, right = 0, len(nums) - 1
while left < right:
mid = left + (right - left) // 2
if nums[mid] < nums[mid + 1]:
left = mid + 1
else:
right = mid
return left
4. Asymptotic Complexity & Edge Cases
| Metric | Complexity | Architectural Justification |
|---|---|---|
| Time Complexity | O(log n) |
Search interval $[\text{left}, \text{right}]$ is halved on every iteration. Maximum iterations = $\lceil \log_2 n \rceil$. |
| Space Complexity | O(1) |
Iterative implementation consumes strictly constant auxiliary memory (three integer pointer variables). |
| Single Element ($n=1$) | O(1) |
left = 0, right = 0. Loop immediately bypasses and returns index 0, matching $nums[-1] = nums[1] = -\infty$. |
| Strictly Monotonic | O(log n) |
If strictly increasing, converges to $n-1$. If strictly decreasing, converges to index 0. |
5. Key Architectural Takeaways for Interview Candidates
In technical interview environments (FAANG/Tier-1 engineering rounds), interviewers select this problem to evaluate candidates' understanding of search invariants:
- Binary Search Does Not Require Global Sorting: It requires only a monotonic decision boundary or a guaranteed path to a solution. As long as you can discard one half of the search space with absolute certainty, binary search is mathematically valid.
- Strictly Handle Edge Invariants: The condition
while (left < right)combined withright = midavoids infinite loops. When only two elements remain (e.g.left = 0, right = 1),mid = 0, andmid + 1 = 1is safely in bounds. Ifnums[0] < nums[1],left = 1and loop exits. Ifnums[0] > nums[1],right = 0and loop exits. - Multiple Peaks Permitted: The problem specification allows returning any peak. You do not need to locate the global maximum; finding any local extremum satisfies all problem constraints.
