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
.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach to finding a peak involves examining each number in the list one by one. For each number, we check if it is larger than its neighbors. If it is, we've found a peak.
Here's how the algorithm would work step-by-step:
def find_peak_element_brute_force(numbers):
list_length = len(numbers)
# Handle edge case of single element list
if list_length == 1:
return 0
# Check if the first element is a peak
if numbers[0] > numbers[1]:
return 0
# Iterate through the middle elements
for index in range(1, list_length - 1):
# Check if current element is greater than its neighbors
if numbers[index] > numbers[index - 1] and numbers[index] > numbers[index + 1]:
return index
# Check if the last element is a peak
if numbers[list_length - 1] > numbers[list_length - 2]:
return list_length - 1
return None
The goal is to find a 'high point' in a collection of numbers without checking every single number. We can use a clever strategy that quickly narrows down where that high point must be by repeatedly cutting the problem in half.
Here's how the algorithm would work step-by-step:
def find_peak_element(nums):
left_index = 0
right_index = len(nums) - 1
while left_index < right_index:
middle_index = (left_index + right_index) // 2
# Check if middle element is greater than its right neighbor.
if nums[middle_index] > nums[middle_index + 1]:
right_index = middle_index
# A peak must exist in the left half
else:
left_index = middle_index + 1
# A peak must exist in the right half.
return left_index
Case | How to Handle |
---|---|
Empty or null input array | Return -1 or throw an exception indicating no peak can be found as an empty array has no peak. |
Array with a single element | Return index 0, as a single element is always a peak. |
Array with two elements where the first is larger | Return index 0 as the first element is the peak. |
Array with two elements where the second is larger | Return index 1 as the second element is the peak. |
Array with elements in strictly increasing order | Return the index of the last element (n-1), as it's a peak according to the implied -infinity boundary. |
Array with elements in strictly decreasing order | Return the index of the first element (0), as it's a peak according to the implied -infinity boundary. |
Array with multiple peak elements | Binary search will naturally converge on one of the peaks, any peak is a valid solution. |
Integer overflow when calculating mid = (left + right) / 2 | Calculate mid as left + (right - left) / 2 to prevent overflow. |