852. Peak Index in a Mountain Array
Description
Let’s call an array arr a mountain if the following properties hold:
arr.length >= 3
There exists some i with 0 < i < arr.length - 1 such that:
arr[0] < arr[1] < ... arr[i-1] < arr[i]
arr[i] > arr[i+1] > ... > arr[arr.length - 1]
Given an integer array arr that is guaranteed to be a mountain, return any i such that arr[0] < arr[1] < ... arr[i - 1] < arr[i] > arr[i + 1] > ... > arr[arr.length - 1]
.
Thoughts
We can traverse the whole list and find the first position i that has arr[i + 1] > arr[i] since there is not dup in the problem. The time complexity is O(n)
We find some regularity in the array. It’s increasing and then decreasing. We can use binary search to see if the peak is in the first half or the last half. This will reduce the time complexity to O(logn)
Exceptions
- No special cases if we use bruteforce to traverse the list.
- It’s important that there’s no duplicate numbers in the array. Otherwise the binary search method will not work. Because for the mid with
nums[mid + 1] == nums[mid]
we cannot identify which part it should be. - To avoid any index out of range or infinite loop, we only consider the binary part when the length of sliced array is larger than 2. For any array that has only 1 or 2 elements, we just compare the elements and return the large one.
Python Code
Brute-force
def peakIndexInMountainArray(self, arr: List[int]) -> int:
for i in range(len(arr) - 1):
if arr[i + 1] < arr[i]:
return i
While-loop Binary Search
def peakIndexInMountainArray(self, arr: List[int]) -> int:
start, end = 0, len(arr) - 1
'''
This is to avoid index out of range or infinite loop
'''
while start < end - 1:
mid = (start + end) // 2
if arr[mid + 1] > arr[mid]:
start = mid
if arr[mid + 1] < arr[mid]:
end = mid
'''
We have 1 or 2 elements after the while loop.
Need to check them and return the large one.
'''
if arr[start] >= arr[end]:
return start
return end
Recursive Binary Search
def peakIndexInMountainArray(self, arr: List[int]) -> int:
return self.binarysearch(arr, 0, len(arr) - 1)
def binarysearch(self, arr, start, end):
'''
This is the same as start < end - 1 in above while-loop.
We only do binary search to the array which has at least
3 elements to avoid index out of range or infinite loop.
In recursive method, we treat them as special cases and check it at the begining.
'''
if start >= end - 1:
if arr[start] >= arr[end]:
return start
return end
mid = (start + end) // 2
if arr[mid + 1] > arr[mid]:
return self.binarysearch(arr, mid, end)
if arr[mid + 1] < arr[mid]:
return self.binarysearch(arr, start, mid)
Summary
We can think of binary search if we see any array related problems which has the up or down trend. We can try binary search as long as we can find rules to check if the result is in the left side and right side.