题目链接:https://leetcode.com/problems/find-peak-element/ 题目:
A peak element is an element that is greater than its neighbors.
num[i] ≠ num[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.
num[-1] = num[n] = -∞
.[1, 2, 3, 1]
, 3 is a peak element and your function should return the index number 2.
Note:
Your solution should be in logarithmic complexity.
思路:
可能包含多个极值点(peak),只要取任意一个就行。假设只有一个peak,用二分查找根据mid元素单增单减的关系可以判断peak在mid的左边还是右边。如果不止一个peak,用二分法划分也不会将查找区间[left,right]划到没有peak的区间。时间复杂度为O(logn)。
算法:
public int findPeakElement(int[] nums) {
int index = -1;
int l = 0, h = nums.length - 1, m = 0;
while (l <= h) {
m = (l + h) / 2;
int r = isPeakElement(nums, m);//判断i跟左右元素关系
if (r == 0) {
return m;
} else if (r == -1) {//单减 peak在左边
h = m - 1;
} else if (r == 1) {//单增peak在右边
l = m + 1;
}
}
return index;
}
/**
* 判断i跟左右元素关系
* -1代表单减 0代表是peak 1代表单增
*/
public int isPeakElement(int[] nums, int i) {
if (nums.length - 1 == i) { // 如果在最右边
if (nums.length - 2 >= 0 && nums[nums.length - 2] < nums[nums.length - 1])//最后一个元素且比前一个元素大,是peak
return 0;
else if (nums.length - 2 < 0)//单元素肯定是peak
return 0;
else if (nums.length - 2 >= 0 && nums[nums.length - 2] < nums[nums.length - 1]) {
return -1;
}
}
if (0 == i) { // 如果在最左边
if (i + 1 < nums.length && nums[i + 1] < nums[i])
return 0;
else if (i + 1 >= nums.length)
return 0;
else if (i + 1 < nums.length && nums[i + 1] > nums[i]) {
return 1;
}
}
// 否则左右都有数
if (nums[i] > nums[i - 1]) {
if (nums[i] > nums[i + 1])
return 0;
else
return 1;
} else {
if (nums[i] > nums[i + 1])
return -1;
else
return 1;
}