前端算法第一四五期-山脉数组的峰顶索引

357 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情

符合下列属性的数组 arr 称为 山脉数组

  • arr.length >= 3

  • 存在 i0 < i < arr.length - 1)使得:

    • arr[0] < arr[1] < ... arr[i-1] < arr[i]
    • arr[i] > arr[i+1] > ... > arr[arr.length - 1]

给你由整数组成的山脉数组 arr ,返回任何满足 arr[0] < arr[1] < ... arr[i - 1] < arr[i] > arr[i + 1] > ... > arr[arr.length - 1] 的下标 i 。

示例 1:

输入:arr = [0,1,0]
输出:1

示例 2:

输入:arr = [0,2,1,0]
输出:1

示例 3:

输入:arr = [0,10,5,2]
输出:1

示例 4:

输入:arr = [3,4,5,1]
输出:2

示例 5:

输入:arr = [24,69,100,99,79,78,67,36,26,19]
输出:2

提示:

  • 3<=arr.length<=104`3 <= arr.length <= 10^4`
  • 0<=arr[i]<=106`0 <= arr[i] <= 10^6`
  • 题目数据保证 arr 是一个山脉数组

枚举

我们可以对数组 arr\textit{arr}arr 进行一次遍历。

当我们遍历到下标 iii 时,如果有 arri1<arri>arri+1arri−1<arri>arri+1,那么 iii 就是我们需要找出的下标。

更简单地,我们只需要让 ii 满足 arri>arri+1arri>arri+1 即可。在遍历的过程中,我们最先遍历到的满足 arri>arri+1arri>arri+1 的下标 i 一定也满足 arri1<arriarri−1<arri

var peakIndexInMountainArray = function(arr) {
    const n = arr.length;
    let ans = -1;

    for (let i = 1; i < n - 1; ++i) {
        if (arr[i] > arr[i + 1]) {
            ans = i;
            break;
        }
    }
    return ans;
};

复杂度分析

  • 时间复杂度:O(n),其中 n 是数组 arr 的长度。我们最多需要对数组 arr 进行一次遍历。
  • 空间复杂度:O(1)。

二分查找

记满足题目要求的下标 i 为 iansians。我们可以发现:

  • i<iansi<ians 时,arri<arri+1arri<arri+1 恒成立;
  • iiansi≥ians 时,arri>arri+1arri>arri+1 恒成立。

这与方法一的遍历过程也是一致的,因此 iansians 即为「最小的满足 arri>arri+1arri>arri+1 的下标 i,我们可以用二分查找的方法来找出 iansians

var peakIndexInMountainArray = function(arr) {
    const n = arr.length;
    let left = 1, right = n - 2, ans = 0;

    while (left <= right) {
        const mid = Math.floor((left + right) /2 );
        if (arr[mid] > arr[mid + 1]) {
            ans = mid;
            right = mid - 1;
        } else {
            left = mid + 1;
        }
    }
    return ans;
};

复杂度分析

  • 时间复杂度:O(logn)O(log⁡n),其中 n 是数组 arrarr 的长度。我们需要进行二分查找的次数为 O(logn)O(log⁡n)
  • 空间复杂度:O(1)。