题目描述
统计一个数字在排序数组中出现的次数。例如输入排序数组[1, 2, 3, 3, 3, 3, 4, 5]和数字3,由于3在这个数组中出现了4次,因此输出4
思路1:
很明显,从头遍历数组,就能统计出3出现的次数,时间复杂度为O(n)
Java 代码如下:
// O(n)的方法
public class Solution {
public int GetNumberOfK(int [] array , int k) {
int count = 0;
for(int i = 0; i < array.length; i++) {
if(array[i] == k) {
count++;
}else if(array[i] > k) {
break;
}
}
return count;
}
}
思路2:
很显然,面试官是不会满意这样的解法。
由于数组已经排好序,因此可以使用二分法,找到k第一次出现的位置和最后一次出现的位置,然后两个位置相减。
Step1. 使用二分法找到第一次出现k的位置,记为first
二分法每次都会找到数组中间的数字,并分为前半段和后半段
- 如果中间数字大于k ,说明k第一次出现的位置,只能在数组的前半段
- 如果中间数字小于k ,说明k第一次出现的位置,只能在数组的后半段
- 如果中间数字等于k ,
- 如果k前面的数字小于k,说明中间就是k第一次出现的位置。
- 如果k前面的数字也等于k,说明k第一次出现的位置只能在前半段
Step2. 使用二分法找到最后一次出现k的位置,记为last
- 如果中间数字大于k ,说明k最后一次出现的位置,只能在数组的前半段
- 如果中间数字小于k ,说明k最后一次出现的位置,只能在数组的后半段
- 如果中间数字等于k ,
- 如果k后面的数字大于k,说明中间就是k最后一次出现的位置。
- 如果k后面的数字也等于k,说明k最后一次出现的位置只能在后半段
Step3. last - first + 1即为k出现的次数
由于整个算法使用了二分法,因此时间复杂度为O(logn)。Java 代码如下:
public class Solution {
// O(logn)的方法
public int GetNumberOfK(int[] array , int k) {
int count = 0;
if(array.length > 0) {
int first = GetFirstK(array, k, 0, array.length - 1);
int last = GetLastK(array, k, 0, array.length - 1);
if(first > -1 && last > -1) {
count = last - first + 1;
}
}
return count;
}
// 获取k第一次出现的位置
public int GetFirstK(int[] array, int k, int start, int end) {
if(start > end) {
return -1;
}
int mid = (start + end) / 2;
if(array[mid] == k) {
if((mid > 0 && array[mid - 1] != k) || mid == 0) {
return mid;
}else {
end = mid - 1;
}
}else if(array[mid] > k) {
end = mid - 1;
}else {
start = mid + 1;
}
return GetFirstK(array, k, start, end);
}
// 获取k最后一次出现的位置
public int GetLastK(int[] array, int k, int start, int end) {
if(start > end) {
return -1;
}
int mid = (start + end) / 2;
if(array[mid] == k) {
if((mid < array.length - 1 && array[mid + 1] != k) || mid == array.length - 1) {
return mid;
}else {
start = mid + 1;
}
}else if(array[mid] > k) {
end = mid - 1;
}else {
start = mid + 1;
}
return GetLastK(array, k, start, end);
}
}