1095、山脉数组中查找目标值:多次双指针算法

1095. 山脉数组中查找目标值

(这是一个 交互式问题 )

给你一个 山脉数组 mountainArr,请你返回能够使得 mountainArr.get(index) 等于 target 最小 的下标 index 值。
如果不存在这样的下标 index,就请返回 -1。

何为山脉数组?如果数组 A 是一个山脉数组的话,那它满足如下条件:
首先,A.length >= 3
其次,在 0 < i < A.length - 1 条件下,存在 i 使得:
A[0] < A[1] < … A[i-1] < A[i]
A[i] > A[i+1] > … > A[A.length - 1]
你将 不能直接访问该山脉数组,必须通过 MountainArray 接口来获取数据:
MountainArray.get(k) - 会返回数组中索引为k 的元素(下标从 0 开始)
MountainArray.length() - 会返回该数组的长度

示例 1:
输入:array = [1,2,3,4,5,3,1], target = 3
输出:2
解释:3 在数组中出现了两次,下标分别为 2 和 5,我们返回最小的下标 2。

理解:双指针问题:重点把握指针边界,是否等于的情况等。

山脉数组,即大小大于3的凸函数,先升后降。题目要求在这个数组中找到target的位置。直观思路为:先找到山脉的山峰peak,并基于此分为两部分,左边为升序列,右边为降序列。因此,先对左边升序列利用二分查找,一旦找到,返回即可(题目要求返回最小的target)。如果左边没有,则针对右边降序列进行二分查找,找到返回即可。如果都没有找到,直接返回-1。

class Solution:
    def findInMountainArray(self, target: int, mountain_arr: 'MountainArray') -> int:
        n =  mountain_arr.length()
        peak, l, r = 0, 0, n-1 
        #二分法寻找peak
        while l<=r:
            mid = l+(r-l)//2
            mid_val  =  mountain_arr.get(mid)
            mid_val_l =  mountain_arr.get(mid-1)
            mid_val_r =  mountain_arr.get(mid+1)
            if mid_val_l<mid_val and mid_val>mid_val_r:
                peak = mid
                break
            elif mid_val_l>mid_val:
                r = mid #注意由于用了mid-1及mid=1, 所以r和l更新为mid即可。不用更新为mid+1或者mid-1.比如[1,2,3]时,更新如果采用后面的,更新mid后,mid+1会为3,超出限制。
            else:
                l = mid
        #针对找到的peak峰值,左右分别寻找,先寻左边升序的,找到直接return
        l ,r = 0, peak
        while l<=r:
            mid = mid = l+(r-l)//2
            mid_val  =  mountain_arr.get(mid)
            if target == mid_val:
                return mid
            elif target < mid_val:
                r = mid-1
            else:
                l = mid+1
        # 降序查找,由于升序降序都用到了peak,因此不用担心target就位于peak。
        l ,r = peak, n-1
        while l<=r:
            mid = mid = l+(r-l)//2
            mid_val  = mountain_arr.get(mid)
            if target == mid_val:
                return mid
            elif target < mid_val:
                l = mid+1
            else:
                r = mid-1
        return -1

其中,基于https://blog.youkuaiyun.com/qq_43152052/article/details/104074701的做法:二分部分也可替换为:
//第一次二分,寻找山脉的山峰
while(left<right){
//取左中位数,因为进入循环,数组一定至少有 2 个元素
//因此,左中位数一定有右边元素,数组下标不会发生越界
int mid=left+((right-left)>>1);
//mid所指的值大于等于mid+1,那么山峰在数组的左边,我们应该向左边逼近
if(mountainArr.get(mid)>=mountainArr.get(mid+1))right=mid;
//mid所指的值小于mid+1,那么山峰在数组的右边,我们应该向右边逼近
else left=mid+1;
}
//根据题意山峰一定存在,所以我们不用特判了
int peak=left;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值