1095. 山脉数组中查找目标值[困难]

1,000 阅读2分钟

问题

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

注意: 对 MountainArray.get 发起超过 100 次调用的提交将被视为错误答案。此外,任何试图规避判题系统的解决方案都将会导致比赛资格被取消。

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

示例 2: 输入:array = [0,1,2,4,2,1], target = 3 输出:-1 解释:3 在数组中没有出现,返回 -1。

思路

所谓山脉数组,其实就是先升序再降序。其中最大的数据将数组分成两部分:一个升序序列,一个降序序列。分开后的两个序列可以使用二分法进行查找数据。现在的关键点是:怎么找到最大数据的下标。

最大数据有个特点,肯定比左边的数据大,也肯定比右边的数据大。再分析一下,如果二分法找到的mid,发现get(mid) < get(mid+1),那么肯定需要往右找;否则肯定需要往左找。剩下的就是边界问题了。一般的二分法,边界为low <= high。而此时需要判断mid+1,因此需要设定边界为low < high。

代码

/**
 * // 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 indexOfMax = findIndexOfMax(mountainArr);
        int left = find(target, mountainArr, 0, indexOfMax, true);
        if (left >= 0) {
            return left;
        }
        int right = find(target, mountainArr, indexOfMax, mountainArr.length()-1, false);
        if (right >= 0) {
            return right;
        }
        return -1;
    }
​
    private int find(int target, MountainArray mountainArr, int low, int high, boolean incr) {
        while (low <= high) {
            int mid = (low + high) / 2;
            int cur = mountainArr.get(mid);
            if (cur == target) {
                return mid;
            } else if (cur > target) {
                if (incr) {
                    high = mid - 1;
                } else {
                    low = mid + 1;
                }
            } else if (cur < target) {
                if (incr) {
                    low = mid + 1;
                } else {
                    high = mid - 1;
                }
            }
        }
        return -1;
    }
​
    private int findIndexOfMax(MountainArray mountainArr) {
        int low = 0;
        int high = mountainArr.length() - 1;
        while (low < high) {
            int mid = (low + high) / 2;
            if (mountainArr.get(mid) < mountainArr.get(mid+1)) {
                low = mid + 1;
            } else {
                high = mid;
            }
        }
        return low;
    }
}

复杂度

时间复杂度:O(logn) 空间复杂度:O(1)

硬广告

欢迎关注公众号:double6