在《编程之美》中有一组关于二分查找的题目,给定一个有序(不降序)数组arr和一个数字v:
1、求任意一个i,使得arr[i]等于v,不存在则返回-1。
2、求最小的一个i,使得arr[i]等于v,不存在则返回-1。
3、求最大一个i,使得arr[i]等于v,不存在则返回-1。
4、求最大的i,使得arr[i]小于v,不存在则返回-1。
5、求最小的i,使得arr[i]大于v,不存在返回-1。
第一个题目最常见,也是最经典的二分查找,对于这个题目,while循环条件可以设置为 min <= max ,在循环内部如果arr[mid]==v,就返回mid,跳出了while就表示没找到。另外,对min和max的更改都可以通过使mid加一或者减一得到。代码如下:
//在数组a中,寻找任何一个i,使a[i]等于x
public int findAnyEqual(int[] a,int x){
return binarySearchForAnyEqual(a, 0, a.length-1, x);
}
public int binarySearchForAnyEqual(int[] a,int s,int e,int val){
int min = s,max = e;
int mid;
while(min<=max){
mid = min+(max-min)/2;
if(a[mid]==val){
return mid;
}else if(a[mid]>val){
max = mid-1;
}else{
min = mid+1;
}
}
return -1; //跳出while循环就表示没有找到
}
对于 第二三个题目,思路是一样的,二三题要考察的是如何处理存在多个相同值的情况,即如果数组中如果存在多个v,我们该怎么办,因为是要找最大的一个,我们在遇到 arr[mid]==v 的时候,可以跟处理arr[mid]<v是一样的,此外还需要注意的是,while循环的条件设置为 min < max-1,这样循环停止的时候min==max-1,我们可以分别比较min和max是否等于v,在while循环里更改min和max值的时候可以令 min = mid,max=mid,而不令mid加一或者减一。第二三题代码如下:
//在一个非降序的数组中,寻找a[i]等于x,若存在多个i,返回最大的一个,不存在返回-1
public int findMaxEqual(int[] a,int x){
return binarySearchForMaxEqual(a, 0, a.length-1, x);
}
public int binarySearchForMaxEqual(int[] a,int s,int e,int val){
int min=s,max=e;
int mid;
while(min<max-1){
mid = min+(max-min)/2;
if(a[mid]<=val){
min = mid;
}else{
max = mid;
}
}
if(a[max]==val){
return max;
}else if(a[min]==val){
return min;
}
return -1;
}
//在一个非降序的数组中,寻找a[i]等于x,如果有多个i,返回最小的一个,不存在返回-1
public int findMinEqual(int[] a,int x){
return binarySearchForMinEqual(a, 0, a.length-1, x);
}
public int binarySearchForMinEqual(int[] a,int s,int e,int val){
int min = s, max = e;
int mid;
while(min<max-1){
mid = min + (max-min)/2;
if(a[mid]>=val){
max = mid;
}else{
min = mid;
}
}
if(a[min]==val){
return min;
}else if(a[max]==val){
return max;
}
return -1;
}
后面两个题的思路跟第二三题是一样的,同样要考虑存在多个值相等的情况,所以while循环条件设置为 min<max-1,然后循环结束的时候min==max-1,此时我们可能找到v,也可能没有找到v。 以第四个题为例,如果没有找到v,那么arr[min]一定小于v,arr[max]一定大于v,如果找到了v,那么arr[max]一定等于v,还需要考察arr[min],代码如下:
//在数组a中,寻找小于x的最大元素,返回其下标
public int findMaxElementLessThan(int[] a,int x){
return binarySearchForMaxElementLessThan(a, 0, a.length-1, x);
}
public int binarySearchForMaxElementLessThan(int[] a,int s,int e,int val){
int min = s,max = e;
int mid;
while(min<max-1){
mid = min+(max-min)/2;
if(a[mid]>=val){ //大于跟等于同等处理
max = mid;
}else{
min = mid;
}
}
if(a[min]==val){
if(min==0){
return -1;
}else{
return min-1;
}
}
return min;
}
//寻找最小的i,使a[i]大于 x
public int findMinElementGreatThan(int[] a,int x){
return binarySearchForMinElementGreatThan(a, 0, a.length-1, x);
}
public int binarySearchForMinElementGreatThan(int[] a,int s,int e,int val){
int min = s,max = e;
int mid;
while(min<max-1){
mid = min+(max-min)/2;
if(a[mid]<=val){ //对小于的处理跟等于一样
min = mid;
}else{
max = mid;
}
}
if(a[max]==val){
if(max==a.length-1){
return -1;
}
return max+1;
}
return max;
}
测试代码:
public static void main(String[] args) {
Solution s = new Solution();
// 0 1 2 3 4 5 6 7 8 9 10 11 12
int[] a = {1,2,2,2,3,3,3,5,6,7,7,7,8};
System.out.println(s.findMinElementGreatThan(a, 1));
}