首页 > 试题广场 >

寻找峰值

[编程题]寻找峰值
  • 热度指数:164085 时间限制: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     
public int findPeakElement (int[] nums) {
        // write code here
        int left = 0;
        int right = nums.length-1;
        while (left < right){
            int mid = left+(right-left)/2;
            if(nums[mid] > nums[mid+1]){
                right = mid;
            } else {
                left = mid+1;
            }
           
        }
        return left;
    }
编辑于 2024-04-12 17:00:45 回复(0)
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @return int整型
     */
    public int findPeakElement (int[] nums) {
        // write code here
        int left = 0;
        int right = nums.length -1;
        while(left < right){
            int mid = left + (right - left) / 2;
            if(nums[mid] > nums[mid + 1]){
                right = mid ;
            }else{
                left = mid + 1;
            }
        }
        return right;
    }
}

编辑于 2023-12-06 16:38:00 回复(0)

采用分治的思想,两侧都会进行查找

  1. 如果区间元素数量大于1,则进行分治

  2. 如果区间元素数量等于1,进行判断

    public class Solution {
     public int findPeakElement (int[] nums) {
         return findPeek(nums, 0, nums.length - 1);
     }
    
     public int findPeek(int[] nums, int l, int r) {
         if (l == r) {  // 区间只有一个元素时进行判断
             if (nums.length == 1) {  // 数组本来就一个元素,则一定是峰值 
                 return l;
             } else {  // 数组大于一个元素
                 if (l > 0 && l < nums.length - 1) {  // 该元素位于中间
                     if (nums[l] > nums[l - 1] && nums[l] > nums[l + 1]) {
                         return l;
                     }
                 } else if (l == 0) {  // 该元素位于左侧
                     if (nums[l] > nums[l + 1]) {  
                         return l;
                     }
                 } else if (r == nums.length - 1) {  // 该元素位于右侧
                     if (nums[r] > nums[r - 1]) {
                         return r;
                     }
                 }
             }
         } else {  // 区间大于一个元素时分治
             int mid = (l + r) >> 1;
             int lres = findPeek(nums, l, mid);  // 找左侧的峰值
             int rres = findPeek(nums, mid + 1, r);  // 找右侧的峰值
             if (lres != -1) return lres;
             if (rres != -1) return rres;
         }
    
         return -1; // 找不到峰值返回-1
     }
    }
发表于 2023-11-11 14:27:48 回复(0)
import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @return int整型
     */
    public int findPeakElement (int[] nums) {
        // write code here
        int min = 0,
            max = nums.length - 1;
        
        while(max - min > 1) {  // not adjacent
            int mid = (min + max) / 2;
                        
            if (nums[mid] > nums[mid + 1]) {    // larger than right, go left
                max = mid;
            } else {    // larger than left, go right
                min = mid;
            }
        }

        return nums[min] > nums[max] ? min : max;

                // 别的答案总是在某一个条件下+1,看不懂为什么
                // 不如得到答案所在的相邻两个结果,选符合条件的那个
                // 二分搜索应该具有对称美
    }
}

发表于 2023-11-10 18:00:06 回复(0)
暴力解法
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param nums int整型一维数组
     * @return int整型
     */
    public int findPeakElement (int[] nums) {
        // write code here
        if (nums == null) {
            return -1;
        }
        
        int[] dum = new int[nums.length+2];
        dum[0] = Integer.MIN_VALUE;
        dum[dum.length-1] = Integer.MIN_VALUE;

        for(int i = 0; i < nums.length; i++) {
            dum[i+1] = nums[i];
        }


        int left = 0;
        int mid = 1;
        int right = 2;

        while (right < dum.length) {
            if (dum[left] < dum[mid] && dum[mid] > dum[right]) {
                return mid-1;
            }
            left++;
            mid++;
            right++;
        }
        return -1;
    }
}


发表于 2023-10-21 17:34:46 回复(0)
  public int findPeakElement (int[] nums) {
        // write code here
        int left = 0;
        int right = nums.length-1;
        int mid = (left+right)/2;
        while(left<right){
            if(left==nums.length-1){
                return nums.length-1;
            }else if(right==0){
                return 0;
            }else if(nums[mid]<nums[mid+1]){
                left = mid+1;
                mid = (left+right)/2;
            }else{
                right = mid;
                mid = (left+right)/2;
            }
        }
        return mid;
    }
发表于 2023-09-23 21:44:21 回复(0)
    public int findPeakElement(int[] nums) {
        int l = 0, r = nums.length - 1;
        while (l + 2 <
                r) {// 保证l到r之间至少有3个数,防止访问越界(访问前一个和后一个)
            int c = (l + r) / 2;
            if (nums[c] > nums[c - 1] &&
                    nums[c] > nums[c + 1]) { // 如果是峰值则返回
                return c;
            } else if (nums[c] < nums[c -
                                      1]) { // 如果不是峰值,那么只有2种情况,要么左边比c大,要么右边比c大,或者2边都比c大,我们只需要在比c大的一半中去找峰值就行了
                r = c - 1;
            } else {
                l = c + 1;
            }
        }
        int max = nums[l];
        int index = l;
        for (int i = l + 1; i <= r; i++) {
            if (max < nums[i]) {
                max = nums[i];
                index = i;
            }
        }
        return index;
    }
发表于 2023-09-13 19:20:01 回复(0)
暴力求解完事
public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @return int整型
     */
    public int findPeakElement (int[] nums) {
        // write code here
        if(nums.length == 2)
            if(nums[0] > nums[1])
                return 0;
            else return 1;    
        for(int i = 1; i < nums.length-1; i++){
            if(nums[i] > nums[i+1] && nums[i] > nums[i-1])
            return i;
            if(nums[i]< nums[i+1] && i == nums.length-2)
            return i+1;
        }
        return 0;
    }
}

发表于 2023-08-10 18:53:22 回复(0)
public int findPeakElement (int[] nums) {
        //二分查找
        //局部峰值  左小  中大  右小
        //返回一个峰值就可以
        //一直往高处走,找一个标杆元素(区间中点)把数组分为两个区间,每次向较高的一边走
        //二分查找,从收尾开始每次取中间值,直到首尾相遇
        //区间收尾相遇的点,就是波峰
        int left=0;
        int right=nums.length-1;
        while(left<right){//当left==right,返回的就是ans
            int mid=(left+right)/2;
            if(nums[mid]>nums[mid+1]){
                right=mid;
            }else{
                left=mid+1;
            }
        }
        return right;

    }

发表于 2023-07-31 21:09:07 回复(0)
public int findPeakElement (int[] nums) {
    // write code here
    int p1=0 ,p2=nums.length-1;
    while(p1<p2){
        int mid=(p1+p2)/2;
        // 考虑奇偶数,一定会存在mid和mid+1
        if(nums[mid]<=nums[p2]){
            p1=mid+1;
        }else{
            p2=mid;
        }
    }
    return p1;
}

发表于 2023-07-01 16:35:07 回复(0)
常见解法
   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)
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param nums int整型一维数组
     * @return int整型
     */
    public int findPeakElement (int[] nums) {

        int num = Integer.MIN_VALUE;
        int index = -1;
        for (int i = 0; i < nums.length; i++) {
            if (num < nums[i]) {
                num = nums[i];
                index = i;
            }
        }
        return index;
    }
}

发表于 2023-03-23 17:57:31 回复(0)
虽然直接求出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)
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @return int整型
     */
    public int findPeakElement (int[] nums) {
        // write code here
        if(nums.length==0 || nums==null){
            return -1;
        }
        int mid;
        int start =0;
        int end=nums.length-1;
        if(nums.length==2){
            return nums[start]>nums[end]?start:end;
        }
        while(start+1<end){
            mid=start+(end-start)/2;
            if(nums[mid]<nums[mid-1]){
                end=mid;
            }else if(nums[mid+1]>nums[mid]){
                start=mid+1;
            }else{
                return mid;
            }
        }
        return nums[start]>nums[end]?start:end;
    }
}


发表于 2023-02-12 14:15:14 回复(0)
二分法实现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 length = nums.length;
        if (nums == null || length == 0) {
            return -1;
        }
        if (length == 1) {
            return 0;
        }
        //时间复杂度为 O(n)
       // for (int i = 0; i < length; i++) {
     //       if (nums[i] > get(i - 1, length, nums) && nums[i] > get(i + 1, length, nums)) {
     //           return i;
     //       }
     //    }
     //    return -1;
        return doFindPeakElement(nums);
    }

    private int doFindPeakElement(int[] nums) {
        int length = nums.length;
        int start = 0;
        int end = length - 1;
        while (start <= end) {
            int mid = (end - start) / 2 + start;
            int left = get(mid-1, length, nums);
            int right = get(mid+1, length, nums);
            if(nums[mid] > left && nums[mid] > right) {
                return mid;
            } else if (nums[mid] <= left) {
                end = mid-1;
            }else {
                start = mid+1;
            }
        }
        return -1;
    }

    private int get(int i, int length, int[] nums) {
        int min = Integer.MIN_VALUE;
        if (i >= length) {
            return min;
        }
        if (i < 0) {
            return min;
        }
        return nums[i];
    }

}




//思路
//O(lgn)
1、利用二分查找算法思想,首先从中间位置开始查找
2、判断中间值比左边和右边值都大则中间值为峰值,否则进行第3步
3、判断中间值小于等于左边值则峰值在左边侧 则 end = mid-1
4、判断中间值大于等于右边值则峰值在右侧 则 start = mid+1

发表于 2022-10-30 15:14:57 回复(1)
测试用例已全部通过,下面进行分析:
1、首先理解题目:峰值,即当前值左右两边的值都比它小,边界只要一边比它小即可
2、分析:(1)如果只有一个数值,直接返回0;
(2)如果有两个数值,谁大就返回谁的下标;
(3)考虑边界:
        a. 左边界,即下标为0的数值,只要它比右边的数值大,那它就是峰值;题目要求只要找出一个峰值就行了,因此这个条件可以优先判断,满足返回即可;
        b. 右边界,即最后一个数值,只要它比左边的数值大,那它就是峰值;剩下所有数值都遍历过之后无峰值才判断该边界条件;
3、上代码:
    public int findPeakElement (int[] nums) {
        if (nums.length == 1){
            return 0;
        }
        if (nums.length == 2){
            if (nums[0] < nums[1]){
                return 1;
            }else {
                return 0;
            }
        }
        int i = 1;
        if (nums[i] < nums[i-1]){
            return i-1;
        }
        for (i = 1; i < nums.length - 1; i++) {
            if (nums[i] > nums[i-1] && nums[i] > nums[i+1]){
                return i;
            }
        }
        if (i == nums.length-1 && nums[i] > nums[i-1]){
            return i;
        }
        return -1;
    }
4、时间复杂度:循环占主导,不难看出时间复杂度为O(n),但未能达到O(logn),你有更好的解法吗?
5、空间复杂度:O(1)

发表于 2022-10-04 10:50:15 回复(0)