162. Find Peak Element
介绍
A peak element is an element that is greater than its neighbors.
Given an input array where 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.
You may imagine that num[-1] = num[n] = -∞.
For example, in array [1, 2, 3, 1]
, 3
is a peak element and your function should return the index number 2
.
题意:对于一个相邻元素互不相等的数组,求其中的峰点。峰点就是这一点的值均比其邻近两结点的值大。num[-1] = num[n] = -∞。
解答
这道题目并不难,编程也容易简单的实现。但是如果想要考虑算法的高效性,又是另外一个方面了。以下是两种方法。
方法一
这种方法是一开始我做出来的结果。时间复杂度为O(n)。
- 对于 0 <= i < n-1,寻找第一个使得num[i] > nums[i+1]的结点。
- 由于数组中任意相邻两点之间都不相等,所以我们能够确定对于找到i,必有num[i] > num[i-1]。
- 因为如果num[i-1] > num[i+1],
那么我们第一步中寻找到的值就是i-1,而不是i. - 并且由于num[-1] = num[n] = -∞,所以如果我们查找得到的值 i=n-1,此时n-1也是峰点。因为已有nums[n-1] > nums[n-2]。
- 因而可以直接返回i,就是第一个遇到的峰值。
class Solution {
public:
int findPeakElement(vector<int>& nums)
{
assert(nums.size() > 0);
int i = 0,n = nums.size();
while(i < n-1)
{
if(nums[i] > nums[i+1])
break;
++i;
}
return i;
}
};
方法二:
参考了LeetCode上的高票答案,采用二分法来查找峰点。感觉这是二分法的又一次高效运用。算法的时间复杂度是O(logn)。
- 初始化left = 0,right = nums.size()-1;
- 在left < right的情况下,计算mid = (left + right)/2。由于相邻两元素之间的值并不相等,必有结果nums[mid] < nums[mid+1]或者nums[mid] > nums[mid+1]。
- 若nums[mid] < nums[mid+1]我们可以去除区间[left,mid],在[mid+1,right]之间继续查找。因为由于num[-1] = num[n] = -∞,因而此时的[mid+1,right]和原来的[left,right]区间有相同的拓扑结构。
即nums[mid+1] > nums[mid],并且 nums[right] > nums[right+1],所以此区间内必然存在峰点。 - 若nums[mid] < nums[mid+1],同样的方法进行判断,会发现[left,mid]之间和原来的[left,right]区间有相同的拓扑结构,即nums[left] > nums[left-1],且 nums[mid] > nums[mid+1]。
- 不断的进行二分,直到left==right,此时就是峰值。
class Solution {
public:
int findPeakElement(vector<int>& nums)
{
int left = 0,right = nums.size()-1;
while(left < right)
{
int mid = (left + right)/2;
if(nums[mid] < nums[mid+1])
left = mid+1;
else
right = mid;
}
return left;
}