题目描述:
统计一个数字在排序数组中出现的次数。
如输入排序数组 {1,2,3,3,3,3,4,5} 和数字3,由于 3 在数组中出现了 4 次,因此输出 4.
解析:
在有序数组中查找一个数可以联想到二分查找。
如例子中,要查找3的次数,二分查找,找到3后,它的左右两边可能都有3,因此两边都要查找,如果3在数组中出现了n次,则时间复杂度O(n),二分查找没有起到作用。
假设我们要在数组中查找 k 的次数。因为数组是有序的,那么只要找到数组中的第一个 k 和最后一个 k 就能够确定出现的次数。
- 那么怎样才能确定是第一个 k 呢?
二分查找 nums[mid] == k 时,且 mid 的前一项不为 k 。如果前一项仍为 k ,则继续用二分查找向前一半查找第一个 k。
- 怎样才能确定是最后一个 k 呢?
二分查找 nums[mid] == k 时,且 mid 的后一项不为 k 。如果后一项仍为 k ,则继续用二分查找向后一半查找最后一个 k。
我们不必查找到每一个 k ,只需查找 2 个 k ,因此时间复杂度 O(logn)。
#include <iostream>
using namespace std;
int GetFirstK(int nums[], int start, int end, int k) {
if (nums == NULL || start > end)
return -1;
int mid = (start + end) >> 1;
int firstK = -1;
if (nums[mid] == k) {
if (mid == start || nums[mid-1] != k) // nums[mid] == k, 且 它的前一个不等于 k ,说明是第一个 k
firstK = mid;
else
firstK = GetFirstK(nums, start, mid-1, k);
} else if (nums[mid] > k) {
firstK = GetFirstK(nums, start, mid-1, k);
} else {
firstK = GetFirstK(nums, mid+1, end, k);
}
return firstK;
}
int GetLastK(int nums[], int start, int end, int k) {
if (nums == NULL || start > end)
return -1;
int mid = (start + end) >> 1;
int lastK = -1;
if (nums[mid] == k) {
if (mid == end || nums[mid+1] != k)
lastK = mid;
else
lastK = GetLastK(nums, mid+1, end, k);
} else if (nums[mid] < k) {
lastK = GetLastK(nums, mid+1, end, k);
} else {
lastK = GetLastK(nums, start, mid-1, k);
}
return lastK;
}
int GetCountsOfK(int nums[], int start, int end, int k) {
if (nums == NULL || start > end)
return 0;
int firstK = GetFirstK(nums, start, end, k);
int lastK = GetLastK(nums, start, end, k);
if (firstK > -1 && lastK > -1)
return lastK - firstK + 1;
return 0;
}
int main() {
int nums[] = {1,2,3,4,4,4,4,4,5,5,6,9};
int k = 4;
cout << GetCountsOfK(nums, 0, sizeof(nums)/sizeof(nums[0])-1, k) << endl;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-15 08:37:18