问题描述:
统计一个数字在排序数组中出现的次数。例如输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3字数组中出现了4次,因此输出4.
问题分析:
方法1:利用二分查找的思想,找到中间数据是不是给定的数字,如果是,则继续前后进行遍历,统计次数。如果不是的话,按照中间数字与给定数字的大小比较,去前半区间或者后半区间去查找。这样的话,时间复杂度就是O(N)(N是数组中元素的个数)。
方法2:上边的办法虽然利用了二分查找的办法,但是时间复杂度仍然是比较高的。如果我们可以找出给定数字在数组中的第一个位置的下标,和最后一个位置的下标,那么给定数字的个数就是比较简单的了。所以我们可以利用二分法的思想,找出给定数字在数组中第一个出现的位置和最后一个出现的位置即可求出个数。
代码实现:
#include<iostream>
using namespace std;
//思路:二分查找的方法,找到第一个k和最后一个k,然后计算个数
int GetFirstKIndex(int arr[], int length, int k, int start, int end)
{
if(start > end)//没有找到
return -1;
//int mid = start + ((end - start)>>1);
int mid = (start + end) /2;
//中间的数据就是k
if(arr[mid] == k)
{
//看是否是第一个k
if((mid > 0 && arr[mid - 1] != k) || mid == 0)//就是第一个k
return mid;
else
end = mid - 1;
}
//中间的数据大于k
else if(arr[mid] > k)
end = mid - 1;
else
start = mid + 1;
return GetFirstKIndex(arr,length,k,start,end);
}
int GetLastKIndex(int arr[],int length, int k, int start, int end)
{
if(start > end)//没有找到
return -1;
int mid = start + ((end - start)>>1);
//中间的数据就是k
if(arr[mid] == k)
{
//是最后一个k
if((mid < length - 1 && arr[mid + 1] != k) || mid == length - 1)
return mid;
//不是最后一个k
else
start = mid + 1;
}
//中间的数据大于k
else if(arr[mid] > k)
end = mid - 1;
else
start = mid + 1;
return GetLastKIndex(arr,length,k,start,end);
}
int GetCountK(int arr[],int length,int k)
{
int count = 0;
if(arr != NULL && length > 0)
{
int first = GetFirstKIndex(arr,length, k, 0,length - 1);
int last = GetLastKIndex(arr,length, k, 0,length - 1);
if(first > -1 && last > -1)
count = last - first + 1;
}
return count;
}
int main()
{
int arr[] = {1,2,3,3,3,3,4,5};
//int ret = GetCountK(arr,sizeof(arr)/sizeof(arr[0]),3);
//int ret = GetCountK(arr,sizeof(arr)/sizeof(arr[0]),5);
int ret = GetCountK(arr,sizeof(arr)/sizeof(arr[0]),8);
cout<< ret<<endl;
system("pause");
return 0;
}