A peak element is an element that is greater than its neighbors.
Given an input array nums, where nums[i] ≠ nums[i+1], find a peak element and return its index.
The array may contain multiple peaks, in that case return the index to any one of the peaks is fine.
You may imagine that nums[-1] = nums[n] = -∞.
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: 1 or 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.
tag:array, binary search
method 1
线性扫描,遍历每一个数,比较是否左边的数要低一点,右边的数要高一点。
当然,如果发现右边的数要低一点,就没有必要再看右边的数是否符合,直接看右边的数的下一个数
public int findPeakElement(int[] nums) {
for (int i = 1; i < nums.length-1; i++) {
if (nums[i] > nums[i+1]){
if (nums[i] > nums[i-1])
return i;
else i++;
}
}
return 0;
}
method 2 binary search
这样的题使用二分查找,一开始还是很惊奇的,因为印象中都是对有序数组才使用二分法,但这是对二分法的误解,要理解二分法的精髓在于在每一步都减少待搜索的区间
考虑本题,一个数mid根据和其右边的数进行比较,可以得到该数是在下降的斜坡上还是在上升的斜坡,如果右边的数更小,可以认为是在下降的斜坡上,那么峰值一定是在mid的左边(包含其本身);如果右边的数更大,可以认为是在上升的斜坡上,那么峰值一定是在mid的右边,所以搜索范围可以限制在mid及其右边的子数组
public int findPeakElement(int[] nums) {
int l = 0, r = nums.length - 1;
while (l < r) {
int mid = (l + r) / 2;
if (nums[mid] > nums[mid + 1])
r = mid;
else
l = mid + 1;
}
return l;
}
当然,比如右边的数比mid更大,是在上升的斜坡中,将舍弃mid左边的子数组中也可能存在peak元素,但本题不是求最大的数,本题只要求找到一个peak即可,甚至边界值(i=0,i=n-1)也算peak,所以才可以这样使用二分法
summary:
- 使用二分法减少搜索空间