欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 能源 > 二分查找题目:寻找峰值

二分查找题目:寻找峰值

2025/2/24 19:28:16 来源:https://blog.csdn.net/stormsunshine/article/details/125756143  浏览:    关键词:二分查找题目:寻找峰值

文章目录

  • 题目
    • 标题和出处
    • 难度
    • 题目描述
      • 要求
      • 示例
      • 数据范围
  • 解法
    • 思路和算法
    • 证明
    • 代码
    • 复杂度分析

题目

标题和出处

标题:寻找峰值

出处:162. 寻找峰值

难度

6 级

题目描述

要求

峰值元素是指其值严格大于左右相邻值的元素。

给定一个长度为 n \texttt{n} n 的整数数组 nums \texttt{nums} nums,找到一个峰值元素并返回其下标。如果数组包含多个峰值,则返回任何一个峰值的下标。

可以假设 nums[-1] = nums[n] = − ∞ \texttt{nums[-1]} = \texttt{nums[n]} = -\infty nums[-1]=nums[n]=

要求时间复杂度是 O(log n) \texttt{O(log n)} O(log n)

示例

示例 1:

输入: nums = [1,2,3,1] \texttt{nums = [1,2,3,1]} nums = [1,2,3,1]
输出: 2 \texttt{2} 2
解释: 3 \texttt{3} 3 是峰值元素,返回其下标 2 \texttt{2} 2

示例 2:

输入: nums = [1,2,1,3,5,6,4] \texttt{nums = [1,2,1,3,5,6,4]} nums = [1,2,1,3,5,6,4]
输出: 1 \texttt{1} 1 5 \texttt{5} 5
解释:可以返回峰值 2 \texttt{2} 2 的下标 1 \texttt{1} 1,或者峰值 6 \texttt{6} 6 的下标 5 \texttt{5} 5

数据范围

  • 1 ≤ nums.length ≤ 1000 \texttt{1} \le \texttt{nums.length} \le \texttt{1000} 1nums.length1000
  • -2 31 ≤ nums[i] ≤ 2 31 − 1 \texttt{-2}^\texttt{31} \le \texttt{nums[i]} \le \texttt{2}^\texttt{31} - \texttt{1} -231nums[i]2311
  • 对于所有有效的 i \texttt{i} i 都有 nums[i] ≠ nums[i + 1] \texttt{nums[i]} \ne \texttt{nums[i + 1]} nums[i]=nums[i + 1]

解法

思路和算法

由于题目要求在长度为 n n n 的数组中寻找峰值的时间复杂度是 O ( log ⁡ n ) O(\log n) O(logn),因此需要使用二分查找的做法寻找峰值。二分查找的过程中需要判断可能存在峰值的下标范围,缩小查找的下标范围。

考虑数组 nums \textit{nums} nums 中的两个相邻下标 i i i j j j 处的元素,其中 0 ≤ i , j < n 0 \le i, j < n 0i,j<n j − i = 1 j - i = 1 ji=1。由于 nums [ i ] ≠ nums [ j ] \textit{nums}[i] \ne \textit{nums}[j] nums[i]=nums[j],因此 nums [ i ] \textit{nums}[i] nums[i] nums [ j ] \textit{nums}[j] nums[j] 的大小关系是 nums [ i ] > nums [ j ] \textit{nums}[i] > \textit{nums}[j] nums[i]>nums[j] nums [ i ] < nums [ j ] \textit{nums}[i] < \textit{nums}[j] nums[i]<nums[j]

nums [ i ] > nums [ j ] \textit{nums}[i] > \textit{nums}[j] nums[i]>nums[j] 时,下标范围 [ 0 , i ] [0, i] [0,i] 中一定存在峰值;当 nums [ i ] < nums [ j ] \textit{nums}[i] < \textit{nums}[j] nums[i]<nums[j] 时,下标范围 [ j , n − 1 ] [j, n - 1] [j,n1] 中一定存在峰值。因此可以根据 nums [ i ] \textit{nums}[i] nums[i] nums [ j ] \textit{nums}[j] nums[j] 的大小关系判断可能存在峰值的下标范围,并在更小的范围内查找峰值。

基于上述思路,可以使用二分查找的做法寻找峰值。

low \textit{low} low high \textit{high} high 分别表示二分查找的下标范围的下界和上界,初始时 low \textit{low} low high \textit{high} high 分别为数组的最小下标和最大下标。每次查找时,取 mid \textit{mid} mid low \textit{low} low high \textit{high} high 的平均数向下取整,比较 nums [ mid ] \textit{nums}[\textit{mid}] nums[mid] nums [ mid + 1 ] \textit{nums}[\textit{mid} + 1] nums[mid+1] 的大小关系(注意当 low < high \textit{low} < \textit{high} low<high 时, mid ≤ n − 2 \textit{mid} \le n - 2 midn2,因此下标 mid + 1 \textit{mid} + 1 mid+1 不会超出数组下标范围),判断可能存在峰值的下标范围,调整查找的下标范围。

  • 如果 nums [ mid ] > nums [ mid + 1 ] \textit{nums}[\textit{mid}] > \textit{nums}[\textit{mid} + 1] nums[mid]>nums[mid+1],则下标范围 [ low , mid ] [\textit{low}, \textit{mid}] [low,mid] 中可能存在峰值,在该下标范围中继续查找。

  • 如果 nums [ mid ] < nums [ mid + 1 ] \textit{nums}[\textit{mid}] < \textit{nums}[\textit{mid} + 1] nums[mid]<nums[mid+1],则下标范围 [ mid + 1 , high ] [\textit{mid} + 1, \textit{high}] [mid+1,high] 中可能存在峰值,在该下标范围中继续查找。

low = high \textit{low} = \textit{high} low=high 时,查找结束,此时 nums [ low ] \textit{nums}[\textit{low}] nums[low] 即为峰值,返回 low \textit{low} low

证明

为了证明上述二分查找做法的正确性,对于 0 ≤ i , j < n 0 \le i, j < n 0i,j<n j − i = 1 j - i = 1 ji=1,需要证明:当 nums [ i ] > nums [ j ] \textit{nums}[i] > \textit{nums}[j] nums[i]>nums[j] 时,下标范围 [ 0 , i ] [0, i] [0,i] 中一定存在峰值;当 nums [ i ] < nums [ j ] \textit{nums}[i] < \textit{nums}[j] nums[i]<nums[j] 时,下标范围 [ j , n − 1 ] [j, n - 1] [j,n1] 中一定存在峰值。可以使用反证法证明。

nums [ i ] > nums [ j ] \textit{nums}[i] > \textit{nums}[j] nums[i]>nums[j] 时,假设下标范围 [ 0 , i ] [0, i] [0,i] 中不存在峰值。由于 nums [ i ] \textit{nums}[i] nums[i] 不是峰值,因此 nums [ i ] < nums [ i − 1 ] \textit{nums}[i] < \textit{nums}[i - 1] nums[i]<nums[i1]。从下标 i − 1 i - 1 i1 向左遍历数组 nums \textit{nums} nums,对于每个下标 k k k,由于 nums [ k + 1 ] \textit{nums}[k + 1] nums[k+1] nums [ k ] \textit{nums}[k] nums[k] 都不是峰值,因此 nums [ k + 1 ] < nums [ k ] < nums [ k − 1 ] \textit{nums}[k + 1] < \textit{nums}[k] < \textit{nums}[k - 1] nums[k+1]<nums[k]<nums[k1],即数组 nums \textit{nums} nums 在下标范围 [ 0 , i ] [0, i] [0,i] 中单调递减。由于 nums [ − 1 ] = − ∞ \textit{nums}[-1] = -\infty nums[1]=,因此必有 nums [ 0 ] > nums [ − 1 ] \textit{nums}[0] > \textit{nums}[-1] nums[0]>nums[1],此时 nums [ 0 ] \textit{nums}[0] nums[0] 是峰值。由此可以得到以下结论。

  • 如果下标范围 [ 1 , i ] [1, i] [1,i] 中存在峰值,则下标范围 [ 0 , i ] [0, i] [0,i] 中存在峰值。

  • 如果下标范围 [ 1 , i ] [1, i] [1,i] 中不存在峰值,则 nums [ 0 ] \textit{nums}[0] nums[0] 是峰值,下标范围 [ 0 , i ] [0, i] [0,i] 中存在峰值。

因此,下标范围 [ 0 , i ] [0, i] [0,i] 中一定存在峰值。

nums [ i ] < nums [ j ] \textit{nums}[i] < \textit{nums}[j] nums[i]<nums[j] 时,利用 nums [ n ] = − ∞ \textit{nums}[n] = -\infty nums[n]=,同理可知下标范围 [ j , n − 1 ] [j, n - 1] [j,n1] 中一定存在峰值。

代码

class Solution {public int findPeakElement(int[] nums) {int low = 0, high = nums.length - 1;while (low < high) {int mid = low + (high - low) / 2;if (nums[mid] > nums[mid + 1]) {high = mid;} else {low = mid + 1;}}return low;}
}

复杂度分析

  • 时间复杂度: O ( log ⁡ n ) O(\log n) O(logn),其中 n n n 是数组 nums \textit{nums} nums 的长度。二分查找的次数是 O ( log ⁡ n ) O(\log n) O(logn),每次查找的时间是 O ( 1 ) O(1) O(1),时间复杂度是 O ( log ⁡ n ) O(\log n) O(logn)

  • 空间复杂度: O ( 1 ) O(1) O(1)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词