【每日一题】LeetCode. 1095. 山脉数组查找目标值

每日一题,防止痴呆 = =

一、题目大意

(这是一个 交互式问题 )

给你一个 山脉数组 mountainArr,请你返回能够使得 mountainArr.get(index) 等于 target 最小 的下标 index 值。

如果不存在这样的下标 index,就请返回 -1。

何为山脉数组?如果数组 A 是一个山脉数组的话,那它满足如下条件:
在这里插入图片描述

注意:

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

为了帮助大家更好地理解交互式问题,我们准备了一个样例 “答案”:https://leetcode-cn.com/playground/RKhe3ave,请注意这 不是一个正确答案。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-in-mountain-array

二、题目思路以及AC代码

这道题看到题目后,发起超过100次调用就视为错误答案?我觉得这都把方法告诉你了,肯定得用O(logn)的方法呀,脑袋里冒出的第一个想法就是二分,当然这个题并不是简单的二分,因为它整体是先上升,再下降的,但可以借用二分的思路。

首先一个方法是官方题解和大多数人的做法。就是使用三次二分,我们的目标还是查找,无非是有两个有序数组被拼到一起了而已,我们可以先进行一次二分,把两个数组的分界点(也就是峰值)找到,然后分别求解两个数组的二分查找问题。

第二个思路是我想得思路,我也不知道我为啥一开始没想到三次二分 = =,我的思路也很容易理解,就是把二分进行扩展。现在我们对于一个数组,只用中值是无法比较出待查目标在哪一边的,而且通常是两边都有,那么我们考虑对一个数组,等分成四份,因为我们需要用更多的间隔点来辅助确认两侧的单调性,从而确定目标值的位置。
在这里插入图片描述

如图,假设上图是数组可视化的结果(横坐标是下标,纵坐标是值),无非就是类似上述的两种情况,利用我们选取的四个等分点,就可以确定目标值的位置,首先,对于在四个区间值域范围里的数,直接就可以确定,唯一比较不确定的就是图中左边横线以上的部分,因为他们不在任何区间的值域内,但他们有一定规律,就是他们一定出现在选取等分点中最大值的附近,所以我们也可以根据此,排除一半的数组元素,与二分法类似,每次操作同样可以排除一半的数组元素,也是O(logn)的复杂度,相比来说比上述提到的三次二分更加简洁,思维比较复杂,可能说的不太明白,可以看后续的代码,双百通过。

下面给出AC代码:

三次二分:

class Solution {
    int binary_search(MountainArray &mountain, int target, int l, int r, int key(int)) {
        target = key(target);
        while (l <= r) {
            int mid = (l + r) / 2;
            int cur = key(mountain.get(mid));
            if (cur == target)
                return mid;
            else if (cur < target)
                l = mid + 1;
            else
                r = mid - 1;
        }
        return -1;
    }
public:
    int findInMountainArray(int target, MountainArray &mountainArr) {
        int l = 0, r = mountainArr.length() - 1;
        while (l < r) {
            int mid = (l + r) / 2;
            if (mountainArr.get(mid) < mountainArr.get(mid + 1))
                l = mid + 1;
            else
                r = mid;
        }
        
        int peak = l;
        int index = binary_search(mountainArr, target, 0, peak, [](int x) -> int{return x;});
        if (index != -1)
            return index;
        return binary_search(mountainArr, target, peak + 1, mountainArr.length() - 1, [](int x) -> int{return -x;});
    }
};

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/find-in-mountain-array/solution/shan-mai-shu-zu-zhong-cha-zhao-mu-biao-zhi-by-leet/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

扩展二分:

/**
 * // This is the MountainArray's API interface.
 * // You should not implement it, or speculate about its implementation
 * class MountainArray {
 *   public:
 *     int get(int index);
 *     int length();
 * };
 */
#define INF 100000

void find(MountainArray& mountainArr, int l, int r, int x, int& ans) {
    if (l >= r) {
        if (mountainArr.get(l) == x) ans = min(ans, l);
        if (mountainArr.get(r) == x) ans = min(ans, r);
        return ; 
    }

    int mid = (l + r) >> 1;
    int left_mid = (l + mid) >> 1;
    int right_mid = (r + mid) >> 1;

    int val[5] = {mountainArr.get(l), mountainArr.get(left_mid), mountainArr.get(mid), mountainArr.get(right_mid), mountainArr.get(r)};
    int idx[5] = {l, left_mid, mid, right_mid, r};

    int max_val_idx = -1;
    int max_val = -1;
    for (int i=0;i<5;i++) {
        if (x == val[i]) 
            ans = min(ans, idx[i]);
        if (val[i] > max_val) {
            max_val = val[i];
            max_val_idx = i;
        } 
    }

    bool flag = false;
    for (int i=0;i<4;i++) {
        if (x > val[i] && x < val[i+1]) {
            find(mountainArr, idx[i] + 1, idx[i+1] - 1, x, ans);
            flag = true;
        }
    }

    if (!flag) {
        if (max_val_idx >= 1)
            find(mountainArr, idx[max_val_idx - 1]+1, idx[max_val_idx]-1, x, ans);
        if (max_val_idx <= 3)
            find(mountainArr, idx[max_val_idx]+1, idx[max_val_idx + 1]-1, x, ans);
    }
}

class Solution {
public:
    int findInMountainArray(int target, MountainArray &mountainArr) {
        int ans = INF;
        find(mountainArr, 0, mountainArr.length() - 1, target, ans);
        if (ans == INF) return -1;
        return ans;
    }
};

如果有问题,欢迎大家指正!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值