题目描述
统计一个数字k在排序数组中出现的次数。
解题思路分析
- 首先,如果数组的长度不是很大的话,遍历的时间复杂度为O(n),但是,这肯定是不行的
- 我们发现这是一个有序数组,很容易就想到二分查找,而且时间复杂度为O(log2n)
- 那么我们如何来使用二分查找找出k出现的个数,其实我们只要找出第一个k出现的位置和最后一个k出现的位置,然后就可以计算出k在此排序数组中
- 那么我们如何计算出第一个和最后一个k出现的位置呢,其实也很简单,利用二分法,当我们查找到k时,检验其前面是不是k,如果是的话,说明这不是第一个k,那么第一个k一定在数组的前半段,递归查找下去,同样的,查找最后一个k时,我们找到一个k时,先检验这个k后面是不是k,如果是的话,那么这个k也不是最后一个k,最后一个k肯定在数组的后半段,这样就可以查找出第一个k和最后一个k出现的位置了
代码实现
public int getNumberOfK(int[] nums, int k) {
if (nums == null || nums.length <= 0) {
return 0;
}
int length = nums.length;
int first = getFirstK(nums, 0, length - 1, k);
int last = getLastK(nums, 0, length - 1, k, length);
return (first != -1) && (last != -1) ? last - first + 1 : 0;
}
//查找第一个k
private int getFirstK(int[] nums, int start, int end, int k) {
while (start <= end) {
int mid = (start + end) >> 1;
if (nums[mid] == k) {
//如果mid前面那个数不是k或者mid已经是第一个数了,那么mid就是第一个k的位置了
if (((mid - 1) > 0 && nums[mid - 1] != k) || mid == 0) {
return mid;
} else {
end = mid - 1;
}
} else if (nums[mid] > k) {
end = mid - 1;
} else {
start = mid + 1;
}
}
return -1;
}
//查找最后一个k
private int getLastK(int[] nums, int start, int end, int k, int length) {
while (start <= end) {
int mid = (start + end) >> 1;
if (nums[mid] == k) {
//如果这个mid后面的那个数不是k或者mid已经到了最后一位,那么mid就是最后一个k的位置
if (((mid + 1) < length && nums[mid + 1] != k) || mid == length - 1) {
return mid;
} else {
start = mid + 1;
}
} else if (nums[mid] < k) {
start = mid + 1;
} else {
end = mid - 1;
}
}
return -1;
}