剑指offer面试题53:在排序数组中查找数字(Java 实现)
程序员文章站
2023-12-28 12:04:40
...
题目:统计一个数字在排序数组中出现的次数. 例如输入排序数组{1,2,3,3,3,3,4,5},由于3在这个数中出现了4次,输出4。
测试用例:
1、功能测试:数组中包含或者不包含要查找的数字;要查找的数字出现一次或者多次。
2、边界测试:查找数组中的最小值、最大值;数组中只有一个数字。
3、负面测试:输入的数组为空。
思路:利用二分查找法的变形分别找到第一个要找的值的下标和最后一个要找的值的下标,时间复杂度为 O(logn)。
如何利用二分查找找到第一个k? 二分查找算法总是先拿数组中间的数组和k作比较.
如果中间数字比k大,那么k只可能出现数组的前半段,下一轮只在数组的前半段查找就可以了.
如果中间数字比k小,那么k只可能出现数组的后半段,下一轮只在数组的后半段查找就可以了.
如果中间数组和k相等,先判断这个数字是不是第一个k.
如果位于中间数字前面的一个数字不是k,那么此时中间的数字刚好就是第一个k.
如果中间数字的前面一个数字也是k,也就是说第一个k肯定在数组的前半段,下一轮仍然需要在数组的前半段查找.
基于同样的思路可以在排序数组中找到最后一个k.
如果中间数字比k大,那么k只能出现在数组的前半段.
如果中间数字比k小,那么k只能出现在数组的后半段.
如果中间数子和k相等,需要判断这个数字是不是最后一个k.
如果位于中间数字后面一个数字不是k,那么此时中间的数字刚好就是最后一个k.
如果中间数字的后面一个数字也是k,也就是说第一个k肯定在数组的后半段,下一轮仍然需要在数组的后半段查找.
public class test_fifty_three {
public int GetNumberOfK(int[] array, int k){
int length = array.length;
if(array == null || array.length == 0)
return 0;
//分别表示第一个k和第二个k的下标
int firstK = getFirstK(array, k, 0, length-1);
int lastK = getLastK(array, k, 0, length-1);
//这里要判断要找的值存不存在
if(firstK != -1 && lastK != -1){
return lastK-firstK+1;
}
return 0;
}
//构造函数用来找到第一个要找的值
private int getFirstK(int[] array, int K, int low, int high){
int mid = (high - low) >> 1;
while(low <= high){
if(array[mid] > K){
high = mid-1;
}
else if(array[mid] < K){
low = mid + 1;
}
else if(mid-1 >= 0 && array[mid-1] == K){
high = mid-1;
}
else {
return mid;
}
mid = (low + high) >> 1;
}
return -1;
}
//构造函数用来找到最后一个要找的值
private int getLastK(int[] array, int K, int low, int high){
int mid = (high - low) >> 1;
int length = array.length;
while(low <= high){
if(array[mid] > K){
high = mid-1;
}
else if(array[mid] < K){
low = mid + 1;
}
else if(mid+1 <= length-1 && array[mid+1] == K){
low = mid+1;
}
else {
return mid;
}
mid = (low + high) >> 1;
}
return -1;
}
}