11 寻找峰值(Find Peak Element)

1 题目

??寻找峰值(Find Peak Element)

lintcode:题号——75,难度——medium

2 描述

??给定一个整数数组(size为n),其具有以下特点:相邻位置的数字是不同的;A[0] < A[1] 并且 A[n - 2] > A[n - 1];假定P是峰值的位置则满足A[P] > A[P-1]且A[P] > A[P+1],返回数组中任意一个峰值的位置。数组保证至少存在一个峰;如果数组存在多个峰,返回其中任意一个就行;数组至少包含 3 个数。

??样例1:

输入:A = [1, 2, 1, 3, 4, 5, 7, 6]
输出:1
解释:

返回任意一个峰顶元素的下标,元素2的下标为1,下标6也同样正确。

??样例2:

输入:A = [1,2,3,4,1]
输出:3
解释:

返回峰顶元素4的下标3。

3 思路

??寻找峰值点,峰值点的特征是点的左边处于递增状态、右边处于递减状态。题中对数组做了一些限定:A[0] < A[1],即起点是递增状态; A[n - 2] > A[n - 1],即到达终点时候是递减状态,且相邻位置的数字不同。需要找到数组中的任意一个峰值即可,可以通过递增递减的状态来寻找,即在任意一个区间中,如果起点递增、终点递减,那这个区间内一定有峰值,通过二分法拆分为“half half”的方式,每次留下一定存在峰值的区间,抛掉不一定存在峰值的区间,最后即可找到。

  1. 取中点;
  2. 比较中点与下一个点,判断当前处于递增还是递减;
  3. 找到起点递增、终点递减这样的一定存在峰值的区间,抛掉另一半不一定存在峰值的区间。
  4. 重复上述过程,直到找到峰值。

3.1 图解

输入:A = [1, 2, 1, 3, 4, 5, 7, 6]
输出:6
解释:

返回任意一个峰顶元素的下标即可,峰值元素7的下标为6。

graph TD A --> A1[\抛掉‘1, 2, 1‘\] A[‘1, 2, 1, 3, 4, 5, 7, 6‘] -- 中间位置元素‘3‘,下一个元素‘4‘,递增<br/>3..4递增,7..6递减,区间必有峰值 --> B B --> B1[\抛掉‘3, 4‘\] B[缩小区间至‘3, 4, 5, 7, 6‘] -- 中间位置元素‘5‘,下一个元素‘7‘,递增<br/>5..7递增,7..6递减,区间必有峰值 --> C C[缩小区间至‘5, 7, 6‘] -- 中间位置元素‘7‘,下一个元素‘6‘,递减<br/>5..7递增,7..6递减,区间必有峰值 --> D C --> C1[/抛掉‘6‘/] D[缩小区间至‘5, 7‘] -- 剩下两个元素取峰值 --> E E(找到目标元素‘7‘,下标‘6‘)

3.2 时间复杂度

??算法的时间复杂度为O(log n)。

3.3 空间复杂度

??算法的空间复杂度为O(1)。

4 源码

??注意事项:

  1. 最后两个元素中取峰值的时候,在逻辑上可以直接取end。

因为在最后一次缩小区间的时候,必定是end = mid的情况。如果最后一次缩小区间是start = mid的情况,则说明在缩小后的区间内start点还是处于递增的状态,start必定还不是峰值,区间还能再缩。

  1. 返回的是序号,不是元素值。

??C++版本:

/**
* @param A: 整数数组
* @return: 任意峰值点的下标序号
*/
int findPeak(vector<int> &A) {
	// write your code here
	if (A.size() < 3)
	{
		return -1;
	}

	int start = 0;
	int end = A.size() - 1;
	int mid = 0;
	while (start + 1 < end)
	{
		mid = start + (end - start) / 2;
		if (A.at(mid) < A.at(mid + 1))
		{
			start = mid;
		}
		if (A.at(mid) > A.at(mid + 1))
		{
			end = mid;
		}
	}

        return end;
}

11 寻找峰值(Find Peak Element)

上一篇:面试题之a==1&&a==2&&a==3和a===1&&a===2&&a===3


下一篇:Git配置SSH KEY