1. 题目
峰值元素是指其值大于左右相邻值的元素。
给你一个输入数组 nums
,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个峰值所在位置即可。
你可以假设 n u m s [ − 1 ] = n u m s [ n ] = − ∞ nums[-1] = nums[n] = -\infty nums[−1]=nums[n]=−∞ 。
1.1 示例
- 示例 1 1 1:
- 输入:
nums = [1, 2, 3, 1]
- 输出: 2 2 2
- 解释: 3 3 3 是峰值元素,你的函数应该返回其索引 2 2 2 。
- 示例 2 2 2:
- 输入:
nums = [1, 2, 1, 3, 5, 6, 4]
- 输出: 1 1 1 或 5 5 5
- 解释: 你的函数可以返回索引 1 1 1,其峰值元素为 2 2 2;或者返回索引 5 5 5,其峰值元素为 6 6 6 。
1.2 说明
- 来源: 力扣(LeetCode)
- 链接: https://leetcode-cn.com/problems/find-peak-element
1.3 提示
- 1 < = n u m s . l e n g t h < = 1000 1 <= nums.length <= 1000 1<=nums.length<=1000 ;
- − 2 31 ≤ n u m s [ i ] ≤ 2 31 − 1 -2^{31} \le nums[i] \le 2^{31} - 1 −231≤nums[i]≤231−1 ;
- 对于所有有效的
i
都有nums[i] != nums[i + 1]
。
1.4 进阶
你可以实现时间复杂度为 O ( l o g N ) O(logN) O(logN) 的解决方案吗?
2. 解法一
2.1 分析
这道题,最最最重要的是条件,条件,条件:
- 两边都是负无穷;
- 只需返回一个波峰的索引即可。
这道题主要的问题是,数组当中可能有很多波峰,也可能只有一个,如果尝试画图,就跟股票信息一样,没有规律,那如何在使用二分法时根据中点值判断我们的二分方向该往何处去?
实际上,你这样想,中点所在地方,可能是某座山的不同位置:山峰、山的下坡处、山的上坡处。如果是山峰,最后会二分终止。关键是在下坡和上坡处如何确定下一次查找的方向,因为我们并不知道山峰在当前 mid
的左边还是右边。对此,记住两个字就可以了,爬山(没错,就是带你去爬山):
- 如果你往下坡方向走,也许可能遇到新的山峰,但是也许是一个一直下降的坡,最后到边界;
- 如果你往上坡方向走,就算最后一直上到边界,由于最边界是负无穷,所以一定能找到山峰。
总的一句话,在找到山峰之前往上坡的方向上继续二分,一定能找到,往下坡的方向可能找到,也可能找不到。
- 作者: 笨熊
2.2 解答
from typing import List
class Solution:
def find_peak_element(self, nums: List[int]) -> int:
left, right = 0, len(nums) - 1
while left <= right:
mid = left + (right - left) // 2
if len(nums) == 1 or (left == 0 and nums[0] >= nums[1]):
return 0
if right == len(nums) - 1 and nums[-1] > nums[-2]:
return len(nums) - 1
if nums[mid - 1] < nums[mid] > nums[mid + 1]:
return mid
elif nums[mid - 1] > nums[mid] > nums[mid + 1]:
right = mid
else: # When in trough, either side is okay.
left = mid
def main():
nums = [1, 2, 1, 3, 5, 6, 4]
sln = Solution()
print(sln.find_peak_element(nums)) # 5
if __name__ == '__main__':
main()
实际上,第 17 17 17 行的 else
包含了两种情况,即:
nums[mid - 1] < nums[mid] < nums[mid + 1]
,此时往右相当于爬山;nums[mid - 1] > nums[mid] < nums[mid + 1]
,此时相当于nums[mid]
在谷底,向任意一边都算是爬山。
- 时间复杂度: l o g 2 ( n ) log_2(n) log2(n)。每一步都将搜索空间减半。因此,总共只需要 l o g 2 ( n ) log_2(n) log2(n) 步。其中
n
为nums
数组的长度;- 空间复杂度: O ( 1 ) O(1) O(1)。只使用了常数空间。