题目
统计一个数字在排序数组中出现的次数。
例如:输入排序数组{1, 2, 3, 3, 3, 3, 4, 5}和数字3,
由于3在这个数组中出现了4次,因此输出4.
看到这个问题的时候我首先想到是:排序数组可以用二分查找法。也可以直接遍历数组统计出现的次数。
接下来看一下解题思路:
思路一:
将该数字依次和数组里的每个值比较,统计出现的次数。
代码示例:
public int GetNumberOfK1(int [] array , int k) {
if (array == null || array.length <= 0) {
return 0;
}
//记录该数字在数组中出现的次数
int count = 0;
for (int i = 0; i < array.length; i++) {
if (k == array[i]) {
count++;
}
}
return count;
}
总结
这里需要注意的是
- 对于这种方法时间复杂度是O(n)
思路二
因为是排序好的数组,所以可以采用二分查找法。首先采用二分查找法找到该数值在数组中第一次和最后一次出现的下标,然后返回总共出现的次数。
代码示例:
public int GetNumberOfK2(int [] array , int k) {
if (array == null || array.length <= 0) {
return 0;
}
int firstIndex = findFirstNumIndex(array, k, 0, array.length - 1);
int lastIndex = findLastNumIndex(array, k, 0, array.length - 1);
if (firstIndex < 0 || lastIndex < 0) {
return 0;
}
return lastIndex - firstIndex + 1;
}
/**
* 查找最后一次出现该数字的下标
* 递归写法
* @param array 数组
* @param k 要统计的值
* @param start 起始下标
* @param end 结束下标
* @return
*/
private int findLastNumIndex(int[] array, int k, int start, int end) {
//如果没有找到返回-1
if (start > end) {
return -1;
}
int middleIndex = (start + end) >> 1;
if (array[middleIndex] < k) {
//在后半段查找
return findLastNumIndex(array, k, middleIndex + 1, end);
} else if (array[middleIndex] > k){
//在前半段查找
return findLastNumIndex(array, k, start, middleIndex - 1);
//中间的值的下一个数值不是要找的那个值,或者已经找到最后一个了,
//则该值就是数组中最后一次出现的要统计的值
} else if(middleIndex < array.length - 1 && array[middleIndex + 1] == k){
//在后半段查找
return findLastNumIndex(array, k, middleIndex + 1, end);
} else {
return middleIndex;
}
}
/**
* 查找第一次出现该数字的下标
* 迭代实现
* @param array 数组
* @param k 要统计的值
* @param start 起始下标
* @param end 结束下标
* @return
*/
private int findFirstNumIndex(int[] array, int k, int start, int end) {
int middleIndex = (start + end) >> 1;
//如果没有找到返回-1
while (start <= end) {
if (array[middleIndex] < k) {
start = middleIndex + 1;
} else if (array[middleIndex] > k){
end = middleIndex - 1;
} else if ((middleIndex > 0 && array[middleIndex - 1] == k)) {
end = middleIndex - 1;
} else {
return middleIndex;
}
middleIndex = (start + end) >> 1;
}
return -1;
}
总结
这里需要注意的是
- 因为二分查找的时间复杂度是O(logn),所以该方法的时间复杂度也是O(logn)。
- 二分查找法可以用递归实现也可以用迭代实现,我这里查找该数字在数组中第一次出现的下标时用的是迭代实现;在查找该数字在数组中最后一次出现的下标时用的是递归实现。