前言
大家好!今天我们来聊聊力扣(LeetCode)上的一道经典题目——山脉数组的峰顶索引。这道题目不仅能帮助我们巩固二分查找的知识,还能提高我们解决复杂问题的能力。话不多说,我们直接进入正题!
题目描述
给定一个长度为
n
n
n 的整数山脉数组 arr
,其中的值递增到一个峰值元素后再递减。我们需要返回峰值元素的下标。
示例
-
示例 1:
- 输入:
arr = [0,1,0]
- 输出:
1
- 输入:
-
示例 2:
- 输入:
arr = [0,2,1,0]
- 输出:
1
- 输入:
-
示例 3:
- 输入:
arr = [0,10,5,2]
- 输出:
1
- 输入:
提示
- 数组长度 3 ≤ a r r . l e n g t h ≤ 1 0 5 3 \leq arr.length \leq 10^5 3≤arr.length≤105
- 数组元素范围 0 ≤ a r r [ i ] ≤ 1 0 6 0 \leq arr[i] \leq 10^6 0≤arr[i]≤106
- 题目数据保证
arr
是一个山脉数组
解题思路
看到这个题目,我们首先想到的是通过遍历数组来找到峰值元素的下标。然而,这样的做法时间复杂度是 O ( n ) O(n) O(n),并不符合题目要求的 O ( log ( n ) ) O(\log(n)) O(log(n))。因此,我们需要使用更高效的方法——二分查找。
二分查找的思路
二分查找的核心思想是通过不断缩小搜索区间来找到目标值。在这道题目中,我们可以通过比较中间元素与其相邻元素的大小来判断峰值的方向。
具体步骤如下:
- 初始化左右指针
left
和right
,分别指向数组的起始和末尾。 - 计算中间位置
mid
。 - 比较
arr[mid]
和arr[mid + 1]
:- 如果
arr[mid] > arr[mid + 1]
,说明峰值在左侧(包括mid
),将right
更新为mid
。 - 否则,说明峰值在右侧,将
left
更新为mid + 1
。
- 如果
- 重复上述步骤,直到
left
和right
重合,此时的索引即为峰值元素的下标。
代码实现
理解了思路后,我们可以很容易地将其转化为代码。以下是 Java 实现:
class Solution {
public int peakIndexInMountainArray(int[] arr) {
int left = 0;
int right = arr.length - 1;
while (left < right) {
int mid = (left + right) / 2;
if (arr[mid] > arr[mid + 1] || mid == right) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
}
代码解释
- 初始化
left
为 0,right
为数组长度减 1。 - 进入
while
循环,只要left
小于right
就继续。 - 计算
mid
为left
和right
的中间位置。 - 判断
arr[mid]
与arr[mid + 1]
的大小:- 如果
arr[mid] > arr[mid + 1]
,更新right
为mid
,表示峰值在左侧。 - 否则,更新
left
为mid + 1
,表示峰值在右侧。
- 如果
- 最后返回
left
,即峰值元素的下标。
总结
这道题目通过山脉数组的特性,让我们更好地理解了二分查找的应用场景。希望大家通过这篇博客,能够掌握在类似问题中如何使用二分查找提高效率。祝大家刷题愉快!