每日一题,防止痴呆 = =
一、题目大意
(这是一个 交互式问题 )
给你一个 山脉数组 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;
}
};
如果有问题,欢迎大家指正!!!