zoukankan      html  css  js  c++  java
  • LeetCode162. 寻找峰值

    题目说了,峰值元素就是大于相邻左右元素的元素,又说了nums[-1] = nums[n] = -∞,所以我们就寻思着,如果nums[0]比nums[1]大,再加上nums[-1]是负无穷,那么nums[0]不就是一个峰值元素了吗。

    如果nums[0]不比nums[1]大,那么我们接着把nums[1]和nums[2]比就好了,如果nums[1]大,也可以认为nums[1]是峰值元素。如果nums[1]不比nums[2]大,就继续往后找。

    这种做法时间复杂度是O(n).

    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 0;
        }
    };
    

    题目希望我们的解法是O(logn)时间复杂度的。
    那就得用二分了。

    一般二分都是在一个有序的数组里查找元素用的,这里数组是无序的,但因为我们只需要找任意一个峰值,所以也是可以用二分进行查找的。

    题目说了nums[-1] = nums[n] = -∞,再加上这题所有的元素都是不相同的(题目说的),所以一定有个元素,比相邻的元素都大。
    就算数组元素是递增的,那么最后一个元素也是峰值元素(因为nums[n] = -∞),递减同理。
    所以题目保证了有解。

    二分的过程是这样的,每次二分出中点mid,将nums[mid]和nums[mid + 1]进行比较,如果nums[mid] < nums[mid + 1],那么右半部分肯定有峰值,
    因为nums[mid + 1]大于mid,而且nums[n]为负无穷,所以右半部分肯定出现了上升又下降这种情况(即出现峰值),所以我们让left = mid + 1(峰值最小也是nums[mid + 1])。

    同理,如果nums[mid] > nums[mid + 1],那么左半部分区间肯定有峰值,因为nums[mid]大于nums[mid + 1],且nums[0]是负无穷,所以从mid + 1往左走,肯定出现了先上升后下降这种情况,
    所以我们让right = mid。

    每次折半查找,最后就找到了峰值元素。

    代码如下:

    class Solution {
    public:
        int findPeakElement(vector<int>& nums) {
            int left = 0, right = nums.size() - 1;
            while(left < right) {
                int mid = (left + right) >> 1;
                if(nums[mid] < nums[mid + 1]) {
                    left = mid + 1;
                } else {
                    right = mid;
                }
            }
            return left;
        }
    };
    
  • 相关阅读:
    Using X++ Code Create Meeting Request in Outlook
    程序员的健康
    LinkType Property
    C#一些实用的,容易被遗忘的特性,经验和技巧
    如何面试程序员(转)
    uniapp:授权(以微信小程序为例)
    C#(Windows窗口):窗口最大化、最小化
    Docker 安装和启用Tomcat
    Docker 安装和启用ngnix
    Uniapp: 扫码(以微信小程序为例)
  • 原文地址:https://www.cnblogs.com/linrj/p/13412520.html
Copyright © 2011-2022 走看看