写在前面:
首先,这道问题,当我们看到"排序数组"这四个字的时候,我们首先想到的应该是使用二分法,但是传统的二分法,只能让我们找到一个索引,当数组中出现多个相同元素的时候,返回的索引不确定。eg:int [] str=new int [] {3,3,3}; 而我们,为了找到数字出现的次数,就要找到这个数字第一个出现的索引firstKey和最后一次出现的索引lastKey,最后的结果=lastKey-firstKey+1.
针对,以上的特点,我们就要对二分法进行一些改进,避免,索引取到了中间的元素。
代码实现:
public static int GetNumberOfK(int[] array, int k) {
// 看到有序,首先要想起二分法
if (array.length == 0) {
return 0;
}
int firstKey = findFirstKey(array, k, 0, array.length - 1); // 找到第一个索引
int lastKey = findLastKey(array, k, 0, array.length - 1); // 找到最后一个索引
if (firstKey != -1 && lastKey != -1) {
return lastKey - firstKey + 1;
}
return 0;
}
public static int findFirstKey(int[] array, int k, int low, int high) {
// 等价于 mid = (low + high)/2;
int mid = (low + high) >> 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;
}
public static int findLastKey(int[] array, int k, int low, int high) {
int mid = (low + high) >> 1;
while (low <= high) {
if (array[mid] > k) {
high = mid - 1;
} else if (array[mid] < k) {
low = mid + 1;
} else if (mid + 1 < array.length && array[mid + 1] == k) {
low = mid + 1;
} else {
return mid;
}
mid = (low + high) >> 1;
}
return -1;
}
总结:
针对二分法来说,也可以使用递归来实现,为了方便大家的理解,本文使用了循环的方式。