题目:统计一个数字在排序数组中出现的次数。例如输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3在这个数组中出现了4次,因此输出4.
思路1:因为是排序很好的想到是二分查找,先知道一个3,然后两边顺序查找,分别找到第一个3和最后一个3,以为数字在长度为n的数组中可能出现O(n)次,所以顺序查找的时间复杂度位O(n).
思路2:更高效的利用二分查找,在当前是3的左右两边有可能还有3(根据前边或后边是否为3来判断2分查找的区域是前半段还是后半段),所以我们可以分别在它的左边和右边继续缩小范围查找3。知道分别找到了第一个3和最后一个3,那么这之间3的个数自然而然就出来了。算法的时间复杂度是O(logn)
public int GetNumberOfK(int [] array , int k) {
int firstIndex = GetFirstIndex(array,k);
int lastIndex = GetLastIndex(array,k);
if(firstIndex != -1 && lastIndex != -1)
return lastIndex - firstIndex + 1;
return 0;
}
private int GetFirstIndex(int [] array , int k) {
int left = 0;
int right = array.length - 1;
int firstIndex = -1;
while(left <= right) {
int mid = (left + right) / 2;
if(array[mid] > k) {
right = mid - 1;
} else if(array[mid] < k) {
left = mid + 1;
} else {
if(mid == 0 || array[mid - 1] != k) {
firstIndex = mid;
break;
} else {
right = mid - 1;
}
}
}
return firstIndex;
}
private int GetLastIndex(int [] array , int k) {
int left = 0;
int right = array.length - 1;
int lastIndex = -1;
while(left <= right) {
int mid = (left + right) / 2;
if(array[mid] > k) {
right = mid - 1;
} else if(array[mid] < k) {
left = mid + 1;
} else {
if(mid == array.length - 1 || array[mid + 1] != k) {
lastIndex = mid;
break;
} else {
left = mid + 1;
}
}
}
return lastIndex;
}