题目主要信息:
  • 给定一个长度为n的数组,返回其中任何一个峰值的索引
  • 峰值元素是指其值严格大于左右相邻值的元素
  • 数组两个边界可以看成是最小,nums[1]=nums[n]=nums[-1] = nums[n] = -\infty
  • 峰值不存在平的情况,即相邻元素不会相等
举一反三:

学习完本题的思路你可以解决如下题目:

BM17.二分查找-I

BM18.二维数组中的查找

BM21.旋转数组

方法:二分查找(推荐使用)

知识点:分治

分治即“分而治之”,“分”指的是将一个大而复杂的问题划分成多个性质相同但是规模更小的子问题,子问题继续按照这样划分,直到问题可以被轻易解决;“治”指的是将子问题单独进行处理。经过分治后的子问题,需要将解进行合并才能得到原问题的解,因此整个分治过程经常用递归来实现。

思路:

因为题目将数组边界看成最小值,而我们只需要找到其中一个波峰,因此只要不断地往高处走,一定会有波峰。那我们可以每次找一个标杆元素,将数组分成两个区间,每次就较高的一边走,因此也可以用分治来解决,而标杆元素可以选择区间中点。

//右边是往下,不一定有坡峰
if(nums[mid] > nums[mid + 1])
    right = mid;
//右边是往上,一定能找到波峰
else
    left = mid + 1;

具体做法:

  • step 1:二分查找首先从数组首尾开始,每次取中间值,直到首尾相遇。
  • step 2:如果中间值的元素大于它右边的元素,说明往右是向下,我们不一定会遇到波峰,但是那就往左收缩区间。
  • step 3:如果中间值大于右边的元素,说明此时往右是向上,向上一定能有波峰,那我们往右收缩区间。
  • step 4:最后区间收尾相遇的点一定就是波峰。

图示:

alt

Java实现代码:

import java.util.*;
public class Solution {
    public int findPeakElement (int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        //二分法
        while(left < right){ 
            int mid = (left + right) / 2;
            //右边是往下,不一定有坡峰
            if(nums[mid] > nums[mid + 1])
                right = mid;
            //右边是往上,一定能找到波峰
            else
                left = mid + 1;
        }
        //其中一个波峰
        return right; 
    }
}

C++实现代码:

class Solution {
public:
    int findPeakElement(vector<int>& nums) {
        int left = 0;
        int right = nums.size() - 1;
        //二分法
        while(left < right){ 
            int mid = (left + right) / 2;
            //右边是往下,不一定有坡峰
            if(nums[mid] > nums[mid + 1])
                right = mid;
            //右边是往上,一定能找到波峰
            else
                left = mid + 1;
        }
        //其中一个波峰
        return right; 
    }
};

Python实现代码

class Solution:
    def findPeakElement(self , nums: List[int]) -> int:
        left = 0
        right = len(nums) - 1
        # 二分法
        while left < right: 
            mid = int((left + right) / 2)
            # 右边是往下,不一定有坡峰
            if nums[mid] > nums[mid+1]: 
                right = mid
            # 右边是往上,一定能找到波峰
            else: 
                left = mid + 1
        # 其中一个波峰
        return right 

复杂度分析:

  • 时间复杂度:O(log2n)O(log_2n),二分法最坏情况对整个数组连续二分,最多能分log2nlog_2n
  • 空间复杂度:O(1)O(1),常数级变量,无额外辅助空间