力扣【二分查找】:852. 山脉数组的峰顶索引

  1. 题目描述:

给定一个长度为 n 的整数 山脉 数组 arr ,其中的值递增到一个 峰值元素 然后递减。

返回峰值元素的下标。

你必须设计并实现时间复杂度为 O(log(n)) 的解决方案。

  1. 算法思路:

按照题目,山峰数组会递增到峰值元素然后递减,因此在山峰的某一侧不会出现相同的数值,但山峰两侧可能出现相同数值,

因为时间复杂度要求为O(log(n)),并且数组的两侧分别单调递增和单调递减,显然应该考虑用二分查找,

又因为数组两侧的单调性不同,假设下标为peak的峰值元素一定具有nums[peak - 1] < nums[peak] && nums[peak] > nums[peak + 1]这样的性质,

而对于除了峰值元素的其他元素,假设下标idx,则一定有nums[idx - 1] < nums[idx] 或者nums[idx] > nums[idx + 1],

那么容易得到,如果mid满足peak要求则mid一定是峰值元素,

而如果mid满足其他两种情况的其中一种,就说明mid位于山坡,相应调整left和right区间即可,

并且因为山峰数组长度大于等于3,上述的判断也不会出现越界

另一种思路:我这里的思路更偏向于把peak当作特殊情况单独处理,但其实可以简化成两个区间,比如nums[idx] < nums[idx + 1]为左侧区间,需要left = mid + 1,

而nums[idx] >= nums[idx + 1]则当作右侧区间,此时peak有可能位于这个区间,于是需要right = mid.

这种思路对之后的第1095题山脉数组查找目标值的优化有很大帮助

  1. 代码:
    时间复杂度:O(log (n))
int peakIndexInMountainArray(vector<int>& arr) {
        int left = 0, right = arr.size() - 1;
        int result = -1;

        while (left + 1 < right) {
            int mid = left + (right - left) / 2;

            if (arr[mid - 1] < arr[mid] && arr[mid] > arr[mid + 1]) {
                result = mid;
                break;
            } else if (arr[mid - 1] < arr[mid]) {
                left = mid;
            } else {
                right = mid;
            }
        }

        return result;
    }

另一种思路:

int peakIndexInMountainArray(vector<int>& arr) {
        int left = 0, right = arr.size() - 1;

        while (left < right) {
            int mid = left + (right - left) / 2;

            if (arr[mid] < arr[mid + 1]) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }

        return left;
    }
posted @ 2026-08-13 14:39  lf123z  阅读(1)  评论(0)    收藏  举报