目录
第一问.寻找第一次出现3的位置,应该如何进行划分区间然后找到正确的位置?
第二问.寻找最后一次出现3的位置,应该如何进行划分区间然后找到正确的位置?
这里用两个问题引入,详细理解二分查找
二分查找思路(划分红蓝区域法)
二分查找中,可以把l和r的指针看做是在划分两个红蓝区域,然后寻找边界目标值
设有q[N]数组,在算法开始时,l的指针是指向-1的,而不是0,且r初始化为n,而不是n-1因为在最初,我们是不知道数组里面元素的任何值的,不知道哪些是蓝色区域,哪些是红色区域。(并不是说不可以l=0,r=n-1,只是这样容易写错,并且需要考虑mid是否需要+1来使得算法满足需求,比较麻烦,且容易出现边界问题死循环)。
伪代码如下
//假设查找数组范围为[0,N-1],需要查找x元素
//伪代码如下
check(x){
return IsBlue(x);//判断是否满足蓝色区域条件
}
l=-1,r=n;
while(l+1!=r){
mid=(l+r)/2
if(check(x))l=mid;//假设l一直是包括蓝色部分区域,r是红色部分区域
else r=mid;
}
return l or r;
这样划分可以很容易来注意二分查找所带来的的边界问题,可看如下例子。
如我们需要在下面的序列中找出第一次出现3的位置和最后一次出现3的位置,且找出第一次出现3位置之前的第一个元素2的位置,最后一次出现3的位置的下一个元素4的位置下标。(也就是2 3 .. 3 4这四个元素的位置)如何进行寻找?
1 2 3 3 3 4
第一问.寻找第一次出现3的位置,应该如何进行划分区间然后找到正确的位置?
如上图,这样进行划分红蓝区域,在输出r,就是第一次出现3的位置了!同时返回l也找到了第一次出现3位置的左边第一个元素的位置也找到了。
第一问的C++和Java代码实现:
C
#include <iostream>
using namespace std;
const int N=6;
int q[N],x;
int binarySearchLower(int q[],int x){
int l=-1,r=sizeof(q)/sizeof(q[0]);
int mid;
while(l+1!=r){
mid=l+r>>1;
if(q[mid]<x)l=mid;
else r=mid;
}
return q[r]==x?r:-1;
}
int main(){
int q[]={1,2,3,3,3,4};
printf("%d",binarySearchLower(q,3));
return 0;
}
Java
public class BinarySearch {
/*
*
* q[]:查找的数组
* x:查找的值
* */
public static int binarySearchLower(int q[],int x){
int l=-1,r=q.length;
while(l+1!=r){
int mid =l+r>>1;//右移一位,相当于除于2:,如1111=>8+4+2+1。
if(q[mid]<x)l=mid;//划分蓝色区域,
else r=mid;//划分到了红色区域
}
return q[r]==x?r:-1;
//如果这里输出l,就是2的位置
}
public static void main(String[] args) {
int q[]=new int[]{1,2,3,3,3,4};
System.out.println(binarySearchLower(q,3));
}
}
第二问.寻找最后一次出现3的位置,应该如何进行划分区间然后找到正确的位置?
如上图所示进行划分,然后再返回l就可以找到最后一次出现3的位置了,如果输出r,就找到了最后一次出现3的位置的下一个元素。
第二问的C++和Java代码实现
c++
#include <iostream>
using namespace std;
const int N=6;
int q[N],x;
int binarySearchUpper(int q[],int x){
int l=-1,r=N;
int mid;
while(l+1!=r){
mid=(l+r)/2;
if(q[mid]>x)r=mid;
else l=mid;
}
return q[l]==x?l:-1;
}
int main(){
int q[]={1,2,3,3,3,4};
printf("%d",binarySearchUpper(q,3));
return 0;
}
Java
public class BinarySearch {
/*
*
* q[]:查找的数组
* x:查找的值
* */
public static int binarySearchUpper(int q[],int x){
int l=-1,r=q.length;
while(l+1!=r){
int mid =l+r>>1;//右移一位,相当于除于2:,如1111=>8+4+2+1。
if(q[mid]>x)r=mid;//划分红色区域,
else l=mid;//划分到了蓝色区域
}
return q[l]==x?l:-1;
}
public static void main(String[] args) {
int q[]=new int[]{1,2,3,3,3,4};
System.out.println(binarySearchUpper(q,3));
}
}