2021-12-03 leetcode 852. 山脉数组的峰顶索引

852. 山脉数组的峰顶索引

难度简单222 收藏 分享 切换为英文 接收动态 反馈

符合下列属性的数组 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
示例

输入: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
0 <= arr[i] <= 106
题目数据保证 arr 是一个山脉数组
进阶:很容易想到时间复杂度 O(n) 的解决方案,你可以设计一个 O(log(n)) 的解决方案吗?

我的解法:

三分法的思路,并没有实现出来

尝试了“三分法”,但是怎么也没写出来。。。

最终暴力解决之:

class Solution:
    def peakIndexInMountainArray(self, arr: List[int]) -> int:
        length = len(arr)
        l, m, r = 0, 1, 2
        while (arr[l] < arr[m]) and (arr[m] > arr[r]) == False:
            l, m, r = l + 1, m + 1, r + 1            
        return m

高赞题解中的“三分法”

[852. 山脉数组的峰顶索]顺序&二分&三分求解 - 山脉数组的峰顶索引 - 力扣(LeetCode) (leetcode-cn.com)

对于查找极值点,也可以采用三分的方法,即用两个点将区间三等分,通过比较两个三等分点可以排除掉左区间或右区间
若左等分点大于右等分点,有两种情况:极大值点在左区间或中区间,所以可以排除右区间
若左等分点小于右等分点,有两种情况:极大值点在中区间或右区间,所以可以排除左区间
这个和前文书中的“三分法”思路是一致的!我没有写出来,是因为if-else分支里,没有减一。且rmid用的是rmid = l + (r - l) // 3 * 2,此题解中用的是rmid = r (r - l) // 3 * 2,二分或是三份,都要从两边往中间逼近,我写的语句没有从两边往中间逼近,故找不到正确答案

class Solution:
    def peakIndexInMountainArray(self, arr: List[int]) -> int:
        # 三分查找最大值
        left, right = 0, len(arr) - 1
        while left < right:
            m = (right - left) // 3
            m1 = left + m
            m2 = right - m
            if arr[m1] > arr[m2]:
                right = m2 - 1  
            else:
                left = m1 + 1
        return left

另一个“三分法”的题解:
【宫水三叶】二分 & 三分极值问题 - 山脉数组的峰顶索引 - 力扣(LeetCode) (leetcode-cn.com)

顾名思义,「三分」就是使用两个端点将区间分成三份,然后通过每次否决三分之一的区间来逼近目标值。
具体的,由于峰顶元素为全局最大值,因此我们可以每次将当前区间分为 [l, m1][l,m1]、[m1, m2][m1,m2] 和 [m2, r][m2,r] 三段,如果满足 arr[m1] > arr[m2]arr[m1]>arr[m2],说明峰顶元素不可能存在与 [m2, r][m2,r] 中,让 r = m2 - 1r=m2−1 即可。另外一个区间分析同理。

class Solution {
    public int peakIndexInMountainArray(int[] arr) {
        int n = arr.length;
        int l = 0, r = n - 1;
        while (l < r) {
            int m1 = l + (r - l) / 3;
            int m2 = r - (r - l) / 3;
            if (arr[m1] > arr[m2]) {
                r = m2 - 1;
            } else {
                l = m1 + 1;
            }
        }
        return r;
    }
}

官方题解:

好吧,官方的暴力法也更有智慧


枚举法
class Solution:
    def peakIndexInMountainArray(self, arr: List[int]) -> int:
        n = len(arr)
        ans = -1

        for i in range(1, n - 1):
            if arr[i] > arr[i + 1]:
                ans = i
                break
        
        return ans

二分法:


二分法,关键是最后一句:最小的满足arr_i > arr_i+1的下标i
class Solution:
    def peakIndexInMountainArray(self, arr: List[int]) -> int:
        n = len(arr)
        left, right, ans = 1, n - 2, 0

        while left <= right:
            mid = (left + right) // 2
            if arr[mid] > arr[mid + 1]:
                ans = mid
                right = mid - 1
            else:
                left = mid + 1
        
        return ans

你可能感兴趣的:(2021-12-03 leetcode 852. 山脉数组的峰顶索引)