
在计算机科学中,"山脉数组"(mountain array)是一种特殊的数组结构,它具有以下明确的特性:
我们的目标是找到这个唯一的峰值索引 i。特别地,问题要求解决方案的时间复杂度必须达到 O(log(arr.length)),这强烈暗示我们需要采用二分查找(Binary Search)策略。
许多开发者在面对 O(logN) 复杂度要求时,会自然想到二分查找。然而,二分查找的实现细节,尤其是在非简单查找场景下,常常容易出错。以下是一个常见的、存在问题的二分查找尝试:
class Solution {
public int peakIndexInMountainArray(int[] arr) {
int low = 0;
int high = arr.length - 1;
int mid = 0;
while (low <= high) {
mid = (low + high) / 2;
// 尝试判断 mid 是否为峰值,但条件过于复杂且不准确
if (mid == 0 || (arr[mid] >= arr[mid - 1]) && (mid == high || arr[mid] >= arr[mid + 1]))
return mid;
// 错误的搜索区间更新逻辑
else if (mid > 0 || arr[mid - 1] > arr[mid]) {
low = mid + 1;
}
high = mid - 1; // 此行无条件执行,导致逻辑混乱
}
return mid;
}
}问题诊断:
在某些情况下,一个简单直观的线性扫描(Linear Scan)方法也能找到峰值。这种方法遍历整个数组,记录当前遇到的最大值及其索引。由于山脉数组的特性,数组中的最大值必然是峰值。
public class Solution {
public static int peakIndexInMountainArray(int[] arr) {
int peakValue = 0; // 初始值应根据实际数据范围调整,或使用arr[0]
int peakIndex = 0;
for (int i = 0; i < arr.length; i++) {
int value = arr[i];
if (value > peakValue) {
peakValue = value;
peakIndex = i;
}
}
return peakIndex;
}
public static void main(String[] args) {
System.out.println("Set 1: " + peakIndexInMountainArray(new int[]{0,1,2})); // 2
System.out.println("Set 2: " + peakIndexInMountainArray(new int[]{0,1,0})); // 1
System.out.println("Set 3: " + peakIndexInMountainArray(new int[]{0,2,1,0})); // 1
System.out.println("Set 4: " + peakIndexInMountainArray(new int[]{0,10,5,2})); // 1
System.out.println("Set 5: " + peakIndexInMountainArray(new int[]{0,100,500,2})); // 2
}
}分析:
要满足 O(logN) 的时间复杂度,我们必须采用二分查找。关键在于如何根据 mid 位置的元素,正确地缩小搜索区间。
核心思想:
利用山脉数组的单调性,我们可以通过比较 arr[mid] 和 arr[mid+1] 来判断 mid 位于上升坡还是下降坡,从而确定峰值的大致方向。
算法步骤:
示例代码:
class Solution {
public int peakIndexInMountainArray(int[] arr) {
int low = 0;
// 搜索范围可以覆盖整个数组。
// 因为题目保证了峰值不在两端,所以实际峰值会在 [1, arr.length - 2] 区间内。
// 但为了通用性,我们通常将 high 初始化为 arr.length - 1。
int high = arr.length - 1;
// 循环条件:当 low == high 时,表示找到了峰值索引
while (low < high) {
int mid = low + (high - low) / 2; // 计算中间索引,防止溢出
// 如果 mid 位于上升坡 (arr[mid] < arr[mid+1])
// 峰值一定在 mid 的右侧,mid 肯定不是峰值
if (arr[mid] < arr[mid + 1]) {
low = mid + 1;
}
// 如果 mid 位于下降坡 (arr[mid] > arr[mid+1])
// 或者 mid 就是峰值
// 峰值可能就是 mid,也可能在 mid 的左侧以上就是山脉数组峰值索引查找:优化与二分查找详解的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号