首页 > 试题广场 >

寻找峰值

[编程题]寻找峰值
  • 热度指数:160044 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定一个长度为n的数组nums,请你找到峰值并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个所在位置即可。
1.峰值元素是指其值严格大于左右相邻值的元素。严格大于即不能有等于
2.假设 nums[-1] = nums[n] =
3.对于所有有效的 i 都有 nums[i] != nums[i + 1]
4.你可以使用O(logN)的时间复杂度实现此问题吗?

数据范围:



如输入[2,4,1,2,7,8,4]时,会形成两个山峰,一个是索引为1,峰值为4的山峰,另一个是索引为5,峰值为8的山峰,如下图所示:
示例1

输入

[2,4,1,2,7,8,4]

输出

1

说明

4和8都是峰值元素,返回4的索引1或者8的索引5都可以     
示例2

输入

[1,2,3,1]

输出

2

说明

3 是峰值元素,返回其索引 2     

本题之所以可以使用二分,使复杂度讲到lgn,是因为题目中的nums[i] != nums[i + 1]条件,当中间元素mid不是峰时,一定有一边比mid中间值大,假设右边的值,即mid+1位置的值大于mid的值,则右边一定存在峰,因为右边的值从mid开始要么是 /\ 这个单调性,要么是 / 这种单调性,两种都一定存在峰

function findPeakElement( nums ) {
    let mid,l=0,r=nums.length;
    while(l <= r) {
        mid = Math.floor((l + r) / 2);
        if (mid+1  nums[mid]) {
            l = mid + 1;
            continue;
        }
        if (mid - 1 >= 0 && nums[mid-1] > nums[mid]) {
            r = mid - 1;
            continue;
        }
        return mid;
    }
    return mid;
}

附加普通解法n复杂度:

function findPeakElement( nums ) {
    let i=1;
    while(i = nums[i-1]) ++i;
    if(i >= nums.length) return nums.length-1;
    else return i-1;
}


发表于 2021-12-22 17:05:30 回复(6)
二分就完事了
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型vector 
     * @return int整型
     */
    int findPeakElement(vector<int>& nums) {
        // write code here
        int left = 0, right = nums.size() - 1;
        while(left < right)
        {
            int mid = (right - left) / 2 + left;
            if(nums[mid] < nums[mid + 1])
                left = mid + 1;
            else
                right = mid;
        }
        return left;
    }
};


发表于 2021-11-01 12:16:38 回复(5)
二分法实现O(log n);
public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @return int整型
     */
    public int findPeakElement (int[] nums) {
        // write code here
        int left = 0;
        int right = nums.length - 1;
        int mid;
        while (left < right) {
            // 找到中间值
            mid = (left + right) >> 1;
            // 只要当前中间值 大于它的下一位,说明当前处于下坡状态,那么往数组的左边遍历,就可以找到峰值
            if(nums[mid] > nums[mid + 1])
                // 因为mid 比 它下一位大,所以当前mid有可能是山峰,这里向左遍历的时候需要把mid包含在内
                right = mid; 
            else 
                // 否则当前中间值小于等于它的下一位时,说明山峰处于上坡状态,向右查找就可以找到峰值
                // 因为mid小于它的下一位,所以这里将left赋值为mid+1,从大的那个数开始向右查找
                left = mid + 1;
        }
        // 此时left 和 right相等时 上面的while退出
        
        // 最终返回 left 或 right都可以
        return right;
    }
}


发表于 2022-10-30 19:40:58 回复(1)
二分法在这个题目不好理解,所以可以直接顺序找波峰,而波峰的出现位置可以非常简单地理解——只要开始比后面的值大,此时的值就是波峰。注意最重要的词是“开始”,也就意味着此时的值是一定比右边大,且比左边也大,因为如果比左边小那么波峰就已经过去了,且波峰正是开始比右边大的值,因为变大过程中一定会遇到波峰。当然需要注意三种特殊情况:一是数组只有一个值,二是第一个值就是波峰,三是最后一个值才是波峰。
import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * @param nums int整型一维数组
     * @return int整型
     */
    public int findPeakElement (int[] nums) {
        // write code here
        //只要开始比后面大,这个就是波峰
        int top = 0;
        if (nums.length == 1) return 0;
        else {
            for (int i = 0; i < nums.length; i++) {
                if (nums[nums.length - 1] > nums[nums.length - 2]) {
                    top = nums.length - 1;
                    break;
                } else if (nums[i] > nums[i + 1]) {
                    top = i;
                    break;
                }
            }
        }
        return top;
    }
}



发表于 2023-03-26 11:22:37 回复(0)
class Solution:
    def findPeakElement(self , nums: List[int]) -> int:
        # write code here
        max_value = max(nums)
        if nums.index(max_value) == 0:
            return 0
        elif nums.index(max_value) == len(nums)-1:
            return len(nums)-1
        else:
            return nums.index(max_value)

# 最大值比较就完了
发表于 2022-04-01 18:11:16 回复(0)
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @return int整型
     */
    public int findPeakElement (int[] nums) {
        // 把端点和长度不够的先判断掉
        if(nums.length == 1 || nums[0] > nums[1]) return 0;
        int n = nums.length;
        if(nums[n - 1] > nums[n - 2]) return n - 1;
        // 二分
        int left = 1, right = n - 2;
        while(left < right){
            int mid = left + ((right - left) >> 1);
            if(nums[mid] < nums[mid + 1]){
                left = mid + 1;
            }else if(nums[mid] > nums[mid + 1]){
                right = mid;
            }else{
                return mid;
            }
        }
        return left;
    }
}

编辑于 2023-07-23 10:20:22 回复(5)
class Solution:
    def findPeakElement(self , nums: List[int]) -> int:
        # write code here
        target=max(nums)

        return nums.index(target)
发表于 2023-12-24 15:13:01 回复(1)
常见解法
   public int findPeakElement (int[] nums) {
        // write code here
        // 两种特殊情况,第一种length为1,
        if(nums.length==1) return 0;
        //第二种峰值在尾部
        if(nums[nums.length-1]>nums[nums.length-2]) return nums.length-1;
        //峰值在中间
        for(int i = 1; i < nums.length-1; i++){
            if(nums[i-1]<nums[i] && nums[i+1]<nums[i]){
                return i;
            }
        }
        //峰值在头部
        return 0;
    }

发表于 2023-05-10 15:22:07 回复(0)
int findPeakElement(int* nums, int numsLen ) {
    int i = 0;
    while(nums[i]<nums[i+1]){
        ++i;
        if(i == numsLen-1) return numsLen-1;
    }
    return i;
    // write code here
}

发表于 2022-03-20 08:49:35 回复(1)
虽然直接求出MAX也可以得出结果,但是还是按照正常的方式来解决
public class Solution {
    public int findPeakElement (int[] nums) {
        // write code here
        int left = 0;
        int right = nums.length - 1;
        int mid = 0;
        while (left < right) {
            mid = (left + right) / 2;
            if (nums[mid] < nums[mid + 1]) left = mid + 1;
            else right = mid;
        }
        return right;

    }
}


发表于 2023-03-19 15:17:07 回复(2)
//题目有个很重要的条件,务必记住:假设 nums[-1] = nums[n] = −∞−∞ 
//因此就有结论:当位置A的左边的值大于位置A的值,那么左边必有峰值。相反的右边的值大于A,则右边必有峰值,其他则A就是峰值。
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型vector 
     * @return int整型
     */
    int findPeakElement(vector<int>& nums) 
    {
        // write code here
        int  begin = 0;
        int end = nums.size()-1;
        while(begin < end)
        {
            int mid = (begin + end) >> 1;
            if(nums[mid] < nums[mid+1])
            {
                begin = mid + 1;
            }
            else if(nums[mid] < nums[mid-1])
            {
                end = mid - 1;
            }
            else 
            {
                return mid;
            }
        }
        return begin;
    }
};


发表于 2023-02-28 16:24:03 回复(0)
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型vector 
     * @return int整型
     */
    int findPeakElement(vector<int>& nums) {
        // 时间复杂度O(logN),空间复杂度O(1)
        if (nums.size() == 1 || nums[0] > nums[1]) return 0;
        int left = 0, right = nums.size() - 1, middle;
        if (nums[right - 1] < nums[right]) return right;
        while (left < right) {
            middle = left + ((right - left) >> 1);
            if (nums[middle] > nums[middle - 1] && nums[middle] > nums[middle + 1])
                return middle;
            else if (nums[middle - 1] > nums[middle]) right = middle;
            else if (nums[middle] < nums[middle + 1]) left = middle;
        }
        return -1;
    }
};

发表于 2022-10-08 17:37:43 回复(0)
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型vector 
     * @return int整型
     */
    int findPeakElement(vector<int>& nums) {
        // write code here
        for(int i=0;i<nums.size()-1;i++){
            if(nums[i+1]<nums[i]){
                return i;
            }
        }
        return nums.size()-1;
    }
};
这个题目甚至不需要二分
发表于 2022-05-10 15:41:38 回复(4)
int findPeakElement(int* nums, int numsLen )
{
  if(numsLen>2)    //数组长度大于2
  {
    for(int i=1;i<numsLen-1;i++)
    {
      if(nums[i] > nums[i-1] && nums[i]> nums[i+1])
      {
        return i;
      }
    }
        
   //处理上面的循环检测不到最后一个元素是否是山峰
   if (nums[numsLen - 1] > nums[numsLen - 2])
       return numsLen-1;
  }
 else    //数组长度小于2
 {
    if(nums[1]>nums[0])
      return 1;
 }
   return 0;
}

发表于 2022-03-09 22:17:30 回复(0)
class Solution:
    def findPeakElement(self , nums: List[int]) -> int:
        return nums.index(max(nums))
一行通过了。。。求指正
发表于 2022-03-08 22:11:35 回复(4)
    int left = 0;
    int right = numsLen - 1;
    while(left < right)
    {
        int mid = (right + left)/2; 
        if(nums[mid] < nums[mid + 1])
            left = mid + 1;
        else
            right = mid;
    }
    return left;

发表于 2022-02-26 22:36:29 回复(2)
题目定义了数组两边的值为最小值,如果数组长度大于0,数组中至少会存在一个峰值。
使用二分查找,每次访问中间的值,如果不满足峰值条件,那就往递增的方向走,一定会遇到峰值,因为边界是最小值。
编辑于 2024-03-20 11:19:41 回复(0)
int findPeakElement(int* nums, int numsLen ) {
    int i=numsLen/2;
    if(numsLen==1)
        return 0;
    if(numsLen==2)
        return nums[0]>nums[1]?0:1;
        
    while(i>0 && i<numsLen-1) {
        if(nums[i]<nums[i+1]) 
            i++;
        else if(nums[i]<nums[i-1]) 
            i--;
        else 
            return i;
        if(i<=0 || i>=(numsLen-1))
            return i;
    }
    return i;
}

编辑于 2024-03-16 09:17:49 回复(0)
官方二分题解是有问题的。也不知道那些用官方题解复制粘贴的,是怎么一本正经得出结论的。
思路:
//走上坡:右侧一定有峰值。这个是母庸置疑的。
//走下坡:右侧可能有峰值也可以没有。但不代表右侧一定没有,左侧就一定会有。比如5、5、4、1、8
所以如果按照题目“严格大于即不能有等于”的要求,要想得到解,走下坡的情况在左侧不满足的时候必须重新开启另一侧分支。


发表于 2024-02-04 20:35:42 回复(0)
#include <vector>
class Solution {
  public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param nums int整型vector
     * @return int整型
     */
    int findPeakElement(vector<int>& nums) {
        // write code here
        vector<int> sign;//标记升降
        sign.push_back(1);//起始标记升
        for (uint i = 0; i < nums.size() - 1; i++) {
            if (nums[i] > nums[i + 1])sign.push_back(-1);
            else if (nums[i] < nums[i + 1])sign.push_back(1);
            else sign.push_back(0);
        }
        sign.push_back(-1);
        for (uint i = 0; i < nums.size(); i++) {
            if ((sign[i]*sign[i + 1]) < 0)return i;
        }
        return false;
    }
};

发表于 2023-08-27 20:25:47 回复(0)