题目描述
请实现有重复数字的有序数组的二分查找。
输出在数组中第一个大于等于查找值的位置,如果数组中不存在这样的数,则输出数组长度加一。
初步代码
一开始我没有认真看这个题,就用之前记忆中的二分查找去做了,代码如下:
import java.util.*;
public class Solution {
/**
* 二分查找
* @param n int整型 数组长度
* @param v int整型 查找值
* @param a int整型一维数组 有序数组
* @return int整型
*/
public int upper_bound_ (int n, int v, int[] a) {
// write code here
int first = 0;
int last = n - 1;
int mid = (first + last)/2;
int finalNum = -1;
while(last >= first){
if(v == a[mid]){
finalNum = mid;
break;
}else if(v > a[mid]){
first = mid + 1;
}else if(v < a[mid]){
last = mid - 1;
}
mid = (first + last)/2;
}
if(finalNum == -1){
return n + 1;
}else{
while(finalNum > 0 && a[finalNum] == a[finalNum-1]){
finalNum--;
}
return finalNum + 1;
}
}
}
结果图例:
结果发现,题目中的要求是要我们找到大于等于查找值的位置,而不是等于,所以这个代码需要改一下。
解决代码
小小的改动了一下,实现了最终的代码:
import java.util.*;
public class Solution {
/**
* 二分查找
* @param n int整型 数组长度
* @param v int整型 查找值
* @param a int整型一维数组 有序数组
* @return int整型
*/
public int upper_bound_ (int n, int v, int[] a) {
// write code here
int first = 0;
int last = n - 1;
int mid = (first + last)/2;
int finalNum = -1;
while(last >= first){
if(v == a[mid]){
finalNum = mid;
break;
}else if(v > a[mid]){
first = mid + 1;
}else if(v < a[mid]){
last = mid - 1;
}
mid = (first + last)/2;
}
if(finalNum == -1){
if(a[n-1] < v){
return n + 1;
}else if(a[0] > v){
return 1;
}else{
return mid + 2;
}
}else{
while(finalNum > 0 && a[finalNum] == a[finalNum-1]){
finalNum--;
}
return finalNum + 1;
}
}
}
适当的分析一下:
如果一段排序好的数组中利用二分查找找一个数字n,并且被查找的数字不小于最小值 不大于最大值时:
- 最终按照等于模式下得到的first指针恰好指向最近的大于n的数,last恰好指向最近的小于n的数,而我们得到的mid因为int类型计算的缘故实际上得到的是最近的小于n的数。
由此我们可以得到利用二分查找找恰好大于或者恰好小于的被查找数的情况。