力扣:山脉数组中查找目标值

题目描述


给你一个 山脉数组 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() - 会返回该数组的长度

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

题目分析


本博客参考题解
通过题目,和给出的数据,很明显这个目标值,可以在峰值的左右两边都出现,但由于是严格的排序关系,最多出现两次,需要给出目标值在山脉数组中下标的较小值。
如果目标值,在峰值左侧出现,无需对右侧进行处理;反之,需要对右侧进行处理。
说了这么多,重点很明显,如何从山脉数组中获取峰值 ?
相信大家都 AC了 力扣:852. 山脉数组的峰顶索引 ,如果没有 请先参考该篇博客
在获取到峰值的下标 pickIndex后,问题转变成在 [ 0 , pickIndex ] 升序区间 ,和 ( pickIndex , mountainArr.length() - 1 ] 降序区间 内二分查找目标值。

/**
 * // This is MountainArray's API interface.
 * // You should not implement it, or speculate about its implementation
 * interface MountainArray {
 *     public int get(int index) {}
 *     public int length() {}
 * }
 */
class Solution {
    public int findInMountainArray(int target, MountainArray mountainArr) {
        // 首先找到 峰值
        int left = 0 , right = mountainArr.length() - 1;
        // 二分查找万能模板
        while(left + 1 < right){
            int mid = left + (right - left) / 2;
            int midValue = mountainArr.get(mid);
            if(midValue > mountainArr.get(mid - 1)){ // 上坡
                left = mid;
            } else { // 下坡
                right = mid;
            }
        }
        int pickIndex = mountainArr.get(left) > mountainArr.get(right) ? left : right;

        int target_index = binary(mountainArr , 0 , pickIndex , target , true);
        // 如果在左侧区间有target 值, 一定是最小值 , 反之需要搜索 右区间
        return target_index != -1 ? target_index : binary(mountainArr , pickIndex + 1 , mountainArr.length() - 1 , target , false);

    }

    // 由于 0 到 pickIndex 升序 , 
    // 而 pickIndex + 1 到 moutainArr.length - 1 是降序 , 
    // 二分查找方式不同 , 故这里用 isLeft 来区分
    public int binary(MountainArray mountainArr , int left , int right , int target , boolean isLeft){
        while(left <= right){
            int mid = left + (right - left) / 2;
            int midValue = mountainArr.get(mid);
            if(midValue == target) return mid;
            else if(midValue < target){
                left = isLeft ? mid + 1 : left;
                right = isLeft ? right : mid - 1;
            } else {
                right = isLeft ? mid - 1 : right;
                left = isLeft ? left : mid + 1;
            }
        }
        return -1;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值