LeetCode OJ 之 Find Peak Element (查找极大元素)

来源:互联网 发布:淘宝网如何投诉卖家 编辑:程序博客网 时间:2024/05/22 14:18

题目:

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.

极大元素是一个比它的相邻元素大的元素。给定一个输入数组,满足num[i] ≠ num[i+1](相邻元素都不相等)找出它的极大元素,并返回它的下标。这个数组可能包含多个极大值,如果是这样的话,返回任意一个极大值的下标都可以。

You may imagine that num[-1] = num[n] = -∞.可以假设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.

Note:

Your solution should be in logarithmic complexity.

要求时间复杂度为对数,即O(lgn)。

思路:

题目的要求是找出任意一个满足先增后减的一个数的下标,即↗↘,由复杂度要求可联想到使用二分法。对于二分法,难点就在于如何确定结果是在左半段数组还是后半段数组中,如果这个确定了就好办了。对于中间的数,如果满足

1、 num[mid-1] < num[mid] && num[mid] > num[mid+1],则可以直接返回mid 。

2、如果满足 num[mid-1] <num[mid] 而不满足 num[mid] > num[mid+1],即三个数是递增趋势 ↗↗,那么从 mid 开始的后半段数组一定存在一个数满足条件。因为如果后半段一直递增的话,则最后一个数满足num[n-2] < num[n-1] , num[n-1] > num[n] = -∞ 。如果后半段不是递增的话,则肯定有一个数满足条件,因为有升有降。

3、同样的道理,如果满足 num[mid] >num[mid+1] 而不满足num[mid-1] < num[mid]) ,即三个数是递减的趋势↘↘,那么从0开始到mid 之间的半段数组中一定存在一个数满足条件。原因与上面的类似。

代码:

class Solution {public:    int findPeakElement(const vector<int> &num)     {        int len = num.size() ;        //首先判断第一个和最后一个元素是否满足条件,如果满足直接返回        if(len == 1 || num[0] > num[1])              return 0;        if(num[len - 2] < num[len - 1])            return len - 1;        //下面对第一个和最后一个之间的数使用二分法判断        int left = 1;        int right =len - 1;        while(left <= right )        {            //二分到最后一个元素,则一定满足条件            if(left == right)                   return left;            int mid = (left + right)/2;            if(num[mid-1] < num[mid] &&  num[mid] > num[mid+1])                return mid;            else            {                if(num[mid-1] < num[mid])                {                    left = mid;                }                else                {                    right = mid;                }            }        }    }};

简化版本道理同上:
class Solution {public:    int findPeakElement(const vector<int> &num)    {        int left=0,right=num.size()-1;        while(left<=right)        {            if(left==right)                return left;            int mid=(left+right)/2;            if(num[mid]<num[mid+1])                left=mid+1;            else                right=mid;        }    }};

虽然本题要求对数时间复杂度,但是线性时间复杂度的代码更简单,也能通过,这里也写一下。对于第一个数 num[0] 如果不满足条件,则后一个数num[1] 一定比它大,对于第i+1 个数,即 num[i] 如果之前的数组还没有找到满足条件的话,说明前面的数组一直是递增的,即↗↗……↗↗,如果当前数 num[i] 满足num[i] < num[i-1] ,即先增后减,那么前一个数符合条件,即可直接返回。

代码:
class Solution {public:    int findPeakElement(const vector<int> &num)    {        int len = num.size();        for(int i = 1 ; i < len ; i++)        {            if(num[i] < num[i-1])                return i-1;        }        return num.size() - 1;    }};



0 0