这三道题目都是二分查找的,通过做着三道题目,对于二分查找有加深了一点认识。之前,一直对二分查找认识保留在对有序数组查找是否有所找值的阶段,如果稍加变化查找的条件,代码写起来就很容易出现问题,阿里巴巴实习生的笔试,就因为没有认真考虑,而漏找了一个错误。
Search in Rotated Sorted Array 是将原本普通二分查找的被查找数组进行了循环移动得到的。从基本二分查找思路考虑,如果想实现二分查找,就必须找到最大值与最小值的分界处,因此,我先进行二分查找边界,初始 b=0,e=n-1,通过每次比较A[(b+e)/2]处与A[e]的大小,若小于,则e移动,反之,b移动,从而二分完成查找。找到最大与最小的分界后,通过基本二分即可,不过有一点需要注意的是,由于最大值可能移动到了左边,需要逻辑上将其后移动n,查找通过取模的方式,找到实际地址。
class Solution {
public:
int search(int A[], int n, int target) {
int b=0,e=n-1;
if(n==1){
if(A[0]==target)return 0;
else return -1;
}
while(A[e]<A[b]){
if(A[(b+e)/2]>A[e]){
b=(b+e)/2+1;
if(A[e]>=A[b])e=(b-1+n)%n;
}
else {
e=(b+e)/2-1;
if(A[e]>=A[b])b=(e+1)%n;
}
}
if(A[b]>target||A[e]<target)return -1;
while(A[b]<=A[e]){
int mid;
if(b>e)
mid=((b+e+n)/2)%n;
else mid=(b+e)/2;
if(A[mid]<target)b=(mid+1)%n;
else if(A[mid]>target)e=(mid-1+n)%n;
else return mid;
}
return -1;
}
};
Search for a Range 是在基本二分查找上改变了输出结果,要求输出查到值存储的区域段,如果使用二分查找找到一个值在向两边迭代直到找到最有和最左的target所在的位置即可
class Solution {
public:
vector<int> searchRange(int A[], int n, int target) {
int left=-1,right=-1;
int l=0,r=n-1;
int flag=0;
int mid=(l+r)/2;
while(l<=r){
mid=(l+r)/2;
if(A[mid]==target){flag=1;break;}
else if(A[mid]>target)r=mid-1;
else l=mid+1;
}
if(flag>0){
l=0;r=mid;
while(l<r){
if(A[l]==target){left=l;break;}
if(A[(l+r)/2]==target) {r=(l+r)/2;l++;}
else if(A[(l+r)/2]<target){
l=(l+r)/2+1;
}
}
left=l;
l=mid;r=n-1;
while(l<r){
if(A[r]==target){right=r;break;}
if(A[(l+r)/2]==target) {l=(l+r)/2;r--;}
else if(A[(l+r)/2]>target){
r=(l+r)/2-1;
}
}
right=r;
}
vector<int >res;
res.push_back(left);
res.push_back(right);
return res;
}
};
Search Insert Position 最接近标准的二分查找,只是在查找不成功时返回插入对应位置即可
class Solution {
public:
int searchInsert(int A[], int n, int target) {
if(n==0||target<A[0])return 0;
if(target>A[n-1])return n;
int left=0,right=n-1;
while(left<=right){
int mid=(left+right)/2;
if(A[mid]==target)return mid;
if(A[mid]>target)right=mid-1;
else left=mid+1;
}
return left;
}
};