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.

 

思路:

一看这道题,我傻眼了。尼玛这么简单的题居然是中等难度。莫非有阴谋? 然后我写了个线性算法试了一下,结果完美的通过了....

class Solution {
public:
    int findPeakElement(const vector<int> &num) {
        int ans;
        if(num.size() == 1) //只有一个数字的情况
            return 0;
        for(int i = 0; i < num.size(); i++)
        {
            if((i == 0 && num[i] > num[i + 1])
                || (i == num.size() - 1 && num[i] > num[i - 1])
                || (num[i] > num[i + 1] && num[i] > num[i - 1]))
            {
                return i;
            }
        }
    }
};

 

然后,我就去讨论圈逛去了,看看到底有什么玄机。一看,果然是有更好的方法。

可以用二分查找,得到O(logN)的算法。

题目中num[i] ≠ num[i+1] 很关键,保证了中间取的值num[mid]与 num[mid + 1]不同,从而相比于num[mid + 1],num[mid]一定位于上坡或下坡。这样不满足峰值条件时,处于上坡就把 l 收缩到mid处,处于下坡就把 r 收缩到 mid 处, 不断收缩,使得最终l与r之间只有一个峰值。

class Solution {
public:
int findPeakElement(const vector<int> &num) {
        int len = num.size();
        if (len == 1) return 0;
        int left = 0, right = len - 1;
        int mid;
        while (left < right - 1) {
            mid = left + (right - left) / 2;
            if (num[mid] > num[mid-1] && num[mid] > num[mid+1]) return mid;
            if (num[mid] < num[mid-1]) right = mid;  // like hill climbing 
            else left = mid;
        }
        return num[left] > num[right] ? left : right;
    }
};