162.寻找峰值
标签: array, binary-search
难度: Medium
通过率: 46.21%
原题链接: https://leetcode.com/problems/find-peak-element/description/
题目描述
峰值元素是指其值严格大于左右相邻值的元素。给定一个从0开始索引的整数数组 nums,找到一个峰值,并返回其索引。如果数组中存在多个峰值,则返回任何一个峰值的索引即可。可以假设 nums[-1] = nums[n] = -∞。解决方案必须在 O(log n) 时间复杂度内完成。
解题思路
为了寻找峰值元素,我们可以利用二分查找算法,以下是具体步骤:
-
初始化两个指针,
left为 0(数组的开始),right为n-1(数组的结束,n为数组的长度)。 -
在每次迭代中,计算中点
mid的索引值mid = left + (right - left) // 2。 -
比较
nums[mid]和nums[mid + 1]的大小:- 如果
nums[mid] > nums[mid + 1],这意味着峰值可能在mid的左边区域,包含mid,因为mid本身有可能是峰值。移动right到mid。 - 否则,峰值在右边,移动
left到mid + 1。
- 如果
-
当
left和right重合时,left指向的就是一个峰值的位置。
这种方法利用二分查找,在每次迭代中将搜索范围缩小一半,并在 nums 中寻找局部峰值,复杂度为 O(log n)。
代码实现
- Python
- C++
- JavaScript
- Java
def find_peak_element(nums):
left, right = 0, len(nums) - 1
while left < right:
mid = left + (right - left) // 2
# 如果中间元素大于其右侧元素,则峰值在左半部分或者中间元素本身
if nums[mid] > nums[mid + 1]:
right = mid
else:
# 否则,峰值在右半部分
left = mid + 1
return left
class Solution {
public:
int findPeakElement(vector<int>& nums) {
int left = 0, right = nums.size() - 1;
while (left < right) {
int mid = left + (right - left) / 2;
// 如果中间元素大于其右侧元素,则峰值在左半部分或者中间元素本身
if (nums[mid] > nums[mid + 1]) {
right = mid;
} else {
// 否则,峰值在右半部分
left = mid + 1;
}
}
return left;
}
};
function findPeakElement(nums) {
let left = 0, right = nums.length - 1;
while (left < right) {
let mid = Math.floor(left + (right - left) / 2);
// 如果中间元素大于其右侧元素,则峰值在左半部分或者中间元素本身
if (nums[mid] > nums[mid + 1]) {
right = mid;
} else {
// 否则,峰值在右半部分
left = mid + 1;
}
}
return left;
}
public class Solution {
public int findPeakElement(int[] nums) {
int left = 0, 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;
}
}
复杂度分析
时间复杂度:,因为我们在每次循环中都将搜索空间减半。
空间复杂度:,因为我们只使用了常量级的额外空间,用于存储指针和中间变量。