A peak element is an element that is strictly greater than its neighbors.
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: 2 Explanation: 3 is a peak element and your function should return the index number 2.
Example 2:
Input: nums = [1,2,1,3,5,6,4] Output: 5 Explanation: Your function can return either index number 1 where the peak element is 2, or index number 5 where the peak element is 6.
Constraints:
1 <= nums.length <= 1000
-231 <= nums[i] <= 231 - 1
nums[i] != nums[i + 1]
for all valid i
.This problem asks to find a peak element in a given array. A peak element is an element that is strictly greater than its neighbors. The solution leverages binary search for an efficient O(log n) time complexity.
Approach:
The core idea is that a peak element must exist. We can use binary search to efficiently locate one. In each iteration of the binary search:
mid = (left + right) // 2
.nums[mid]
with nums[mid + 1]
.
nums[mid] > nums[mid + 1]
: This means there's a potential peak to the left of mid
, so we update the search space by setting right = mid
.nums[mid] < nums[mid + 1]
: This suggests a potential peak to the right of mid
, so we update left = mid + 1
.left
and right
converge to a single index, which will be the index of a peak element.Time and Space Complexity:
Code Implementation (Python):
class Solution:
def findPeakElement(self, nums: List[int]) -> int:
left, right = 0, len(nums) - 1
while left < right:
mid = (left + right) // 2
if nums[mid] > nums[mid + 1]:
right = mid # Potential peak on the left
else:
left = mid + 1 # Potential peak on the right
return left # left and right converge to the peak index
Code Implementation (Java):
class Solution {
public int findPeakElement(int[] nums) {
int left = 0, right = nums.length - 1;
while (left < right) {
int mid = (left + right) / 2;
if (nums[mid] > nums[mid + 1]) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
}
Code Implementation (C++):
class Solution {
public:
int findPeakElement(vector<int>& nums) {
int left = 0, right = nums.size() - 1;
while (left < right) {
int mid = left + (right - left) / 2; // Avoid potential overflow
if (nums[mid] > nums[mid + 1]) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
};
Code Implementation (Go):
func findPeakElement(nums []int) int {
left, right := 0, len(nums)-1
for left < right {
mid := (left + right) / 2
if nums[mid] > nums[mid+1] {
right = mid
} else {
left = mid + 1
}
}
return left
}
Code Implementation (TypeScript):
function findPeakElement(nums: number[]): number {
let left = 0, right = nums.length - 1;
while (left < right) {
let mid = Math.floor((left + right) / 2);
if (nums[mid] > nums[mid + 1]) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
All these implementations follow the same binary search algorithm, ensuring an efficient solution to the problem. The choice of language affects only syntactic details, not the core logic or complexity.