这道题大意是给出一个山脉数组,山脉数组的特点是长度不小于3,有一个数为山顶,这个数左边是递增数组,右边是递减数组,求出数组第一个出现值为target的数的下标,如果没有返回-1。数组最大长度能到10000,不能去遍历这个数组,因为最多只能访问100次数组,那么首先我想到的方法就是二分。整个数组又不是按序排列的,不能直接二分,应该先想办法去找到山顶,之后就好做了。首先把数组大概五等分,求出第二三四个点的数的值,这三个点可能出现有三种情况,第一个数>=第二个数且第二个数>=第三个数,第一个数<=第二个数且第二个数>=第三个数,第一个数<=第二个数且第二个数<=第三个数,这三种情况分别可以获取新的山顶所在的范围,详情见代码,注意这里的边界要处理好,否则可能陷入一直递归的情况。如果当前范围小于等于三,那么就可以确定山顶在范围中,依次验证每个点直到确定出山顶即可。确定完山顶之后其余的就简单了,在山顶左右两边分别二分去求是否出现target,如果出现了取较小的坐标值,否则返回-1。
/**
* // 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();
* };
*/
class Solution {
public:
int len;
int num[10005],vis[10005];
int get_index(MountainArray &mountainArr,int left,int right)
{
if(right-left<=2)
{
for(int i=left;i<=right;i++)
{
if(i<=0||i>=len-1) continue;
int save[3];
for(int j=-1;j<=1;j++)
{
if(!vis[i+j])
{
vis[i+j]=1;
num[i+j]=mountainArr.get(i+j);
}
save[j+1]=num[i+j];
}
if(save[1]>save[0]&&save[1]>save[2])
return i;
}
return -1;
}
int mid=(right+left)/2;
int pos1=(mid+left)/2,pos2=mid,pos3=(mid+right)/2;
int val1,val2,val3;
// cout<<pos1<<' '<<pos2<<' '<<pos3<<endl;
if(!vis[pos1])
{
num[pos1]=mountainArr.get(pos1);
vis[pos1]=1;
}
if(!vis[pos2])
{
num[pos2]=mountainArr.get(pos2);
vis[pos2]=1;
}
if(!vis[pos3])
{
num[pos3]=mountainArr.get(pos3);
vis[pos3]=1;
}
if(num[pos1]>=num[pos2]&&num[pos2]>=num[pos3])
{
// cout<<1<<endl;
return get_index(mountainArr,left,pos3-1);
}
if(num[pos1]<=num[pos2]&&num[pos2]>=num[pos3])
{
// cout<<2<<endl;
return get_index(mountainArr,pos1+1,pos3-1);
}
if(num[pos1]<=num[pos2]&&num[pos2]<=num[pos3])
{
// cout<<3<<endl;
return get_index(mountainArr,pos1+1,right);
}
return -1;
}
int findInMountainArray(int target, MountainArray &mountainArr) {
int ans=0;
len=mountainArr.length();
int i=get_index(mountainArr,0,len-1);
int pos=-1;
int left=0,right=i,mid;
while(left<=right)
{
mid=(left+right)/2;
if(!vis[mid])
num[mid]=mountainArr.get(mid);
if(num[mid]<target)
left=mid+1;
else if(num[mid]>target)
right=mid-1;
else
{
pos=mid;break;
}
}
if(pos==-1)
{
left=i;
right=len-1;
while(left<=right)
{
mid=(left+right)/2;
if(!vis[mid])
num[mid]=mountainArr.get(mid);
if(num[mid]>target)
left=mid+1;
else if(num[mid]<target)
right=mid-1;
else
{
pos=mid;break;
}
}
}
return pos;
}
};