[leetcode][search] 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.

click to show spoilers.

Note:

Your solution should be in logarithmic complexity.

方法一:顺序查找 O(n),比较2n次 
class Solution {
public:
    int findPeakElement(vector<int>& nums) {
	int n = nums.size();
	if (nums.empty())  return -1;
	for (int i = 1; i < n - 1; ++i){//寻找数组中间的peak
		if (nums[i] > nums[i - 1] && nums[i] > nums[i + 1]) return i;
	}
	return nums[0] > nums[n-1] ? 0 : n-1;//数组中间没有peak,返回数组首尾的较大者(此时,数组的形状可能有3种:单调递增、单调递减、先单调递减再单调递增)
}
};

方法二:还是 O(n),但是仅比较n次 

因为nums[-1] 为负无穷,所以nums[0]大于nums[-1],这是一个上升的趋势,接下来我们只要找到第一个出现下降趋势的点,即nums[i] < nums[i-1],即为peak,如果不存在这样的点,说明数组是单调递增的,而nums[n]为负无穷,所以nums[n-1]即为peak。

class Solution {
public:
    int findPeakElement(vector<int>& nums) {
	for (int i = 0; i < nums.size()-1; ++i){
		if (nums[i] > nums[i + 1]) return i;
	}
	return nums.size() - 1;
}
};


方法三:折半查找 O(logn),每次递归规模减半
class Solution {
public:
    int findPeakElement(vector<int>& nums) {
	if (nums.empty()) return -1;
	int n = nums.size();
	int index = nums[0] > nums[n - 1] ? 0 : n - 1;
	findPeakElementCore(nums, 0, n-1, index);
	return index;
}
private:
   bool findPeakElementCore(vector<int> &nums, int start, int end, int &index){//寻找不在端点的peak
	int len = end - start + 1;
	if (len < 3) return false;
	int mid = (start+end)>>1;
	if (nums[mid] > nums[mid - 1]){
		if (nums[mid] > nums[mid + 1]){//找到peak
			index = mid;
			return true;
		}
		else findPeakElementCore(nums, mid, end, index);//单调递增,在右边找,因为nums[n]为负无穷
	}
	else return findPeakElementCore(nums, start, mid, index);//单调递减,在左边找,因为nums[-1]为负无穷;或先递减再递增,此时任意一边找都可以因为nums[0]和nums[n]都为负无穷
}
};

非递归实现:

class Solution {
public:
    int findPeakElement(vector<int>& nums) {
	if (nums.empty()) return -1;
	int n = nums.size();
	int index = nums[0] > nums[n - 1] ? 0 : n - 1;
	int left = 0, right = n - 1;
	while (left < right){
		int mid = (left + right) >> 1;
		if (nums[mid] < nums[mid + 1]) left = mid+1;单调递增, 再右半边查找
		else right = mid;//单调递减,在左半边查找
	}
	return left;//循环结束时left == right
}
};


注:本问题的实质是寻找第一个比它的后继大的点,若找到返回它的位置,若找不到(单调递增)返回最后一个位置。这样,该问题就简化为了一个普通的查找问题,并且可以用折半查找(即二分查找)以将时间复杂度降为O(logn)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值