题目描述:统计一个数字在 排序数组中出现的次数。
思路:既然是排序数组,作为二分查找的必要条件,应该立马想到二分查找算法。这道题要求统计某个数字在数组中出现的次数,因此二分查找的应用可以采用不同方式:
一、直接用二分查找法找到一个目标数字,然后在该位置前后两边顺序扫描,找出第一个和最后一个目标数字,这种算法的效率和直接从头到尾顺序扫描整个数组统计目标数字个数的方法是一样的;
二、利用二分查找法分别找到第一个和最后一个目标数字,发挥了二分查找法的效率。
三、如果所给数组的元素都是整数,假设目标数字是整数key,那么可以通过二分法查找key-0.5和key+0.5在该数组中的插入位置,所有key都应该位于(key-0.5,key+0.5)这个区间当中,通过这两个数的插入位置可以直接计算出key在数组中的个数。
方法一
利用一次二分查找算法:
class Solution {
public:
int GetNumberOfK(vector<int> data ,int k) {
if(data.empty())
return 0;
int mid=biSearch(data,k);
if(mid<0) //如果没有找到k,此时mid==-1,直接返回0
return 0;
int i=mid-1,j=mid+1;
int count=1;
while(i>=0&&data[i--]==k) //从mid向左边顺序查找并计数
count++;
while(j<=data.size()-1&&data[j++]==k)//从mid向右边查找并计数
count++;
return count;
}
int biSearch(vector<int> data,int k){
int begin=0,end=data.size()-1;
int mid;
while(begin<=end){
mid=(begin+end)>>1;
if(data[mid]==k)
return mid;
else if(data[mid]<k)
begin=mid+1;
else
end=mid-1;
}
return -1;
}
};
方法二
利用两次二分查找算法分别找到第一个和最后一个目标数字:
class Solution {
public:
int GetNumberOfK(vector<int> data ,int k) {
if(data.empty())
return 0;
int left=GetFirstK(data,k,0,data.size()-1);
int right=GetLastK(data,k,0,data.size()-1);
int count=0;
if(left!=-1&&right!=-1)
count=right-left+1;
return count;
}
int GetFirstK(vector<int> data,int k,int begin,int end){//用递归方式实现二分查找
if(begin>end)
return -1;
int mid=(begin+end)>>1;
if(data[mid]==k){
if((mid>0&&data[mid-1]!=k)||mid==0)
return mid;
else
end=mid-1;
}
else if(data[mid]>k)
end=mid-1;
else
begin=mid+1;
return GetFirstK(data,k,begin,end);
}
/*
int GetFirstK(vector<int> data,int k,int begin,int end){//另外一种写法的递归方式实现二分查找
if(begin>end)
return 0;
int mid=(begin+end)>>1;
if(data[mid]>k)
return GetFirstK(data,k,begin,mid-1);
else if(data[mid]<k)
return GetFirstK(data,k,mid+1,end);
else if(mid>0&&data[mid-1]==k)
return GetFirstK(data,k,begin,mid-1);
else
return mid;
}
*/
int GetLastK(vector<int> data,int k,int begin,int end){//用循环方式实现二分查找
int mid;
while(begin<=end){
mid=(begin+end)>>1;
if(data[mid]>k)
end=mid-1;
else if(data[mid]<k)
begin=mid+1;
else if(mid<data.size()-1&&data[mid+1]==k)
begin=mid+1;
else
return mid;
}
return -1;
}
};
方法三
在数组元素均为整数的情况下可以利用这种方法。利用二分查找法查找目标数字k前后两个浮点数的插入位置,即k-0.5, k+0.5在数组中的插入位置,这两个浮点数中间即为所有的k。
class Solution {
public:
int GetNumberOfK(vector<int> data ,int k) {
if(data.empty())
return 0;
return biSearch(data,k+0.5)-biSearch(data,k-0.5);
}
int biSearch(vector<int> data, double key){
int begin=0,end=data.size()-1;
int mid;
while(begin<=end){
mid=(begin+end)>>1;
if(data[mid]>key)
end=mid-1;
else
begin=mid+1;
}
return begin; //begin==end时结束循环,因此该条语句等价于return end;
}
};
查找k-0.5的插入位置时,返回的结果是第一个k的前一个元素的下标,查找k+0.5的插入位置时,返回的结果是最后一个k的下标,因此两个下标直接相减即为k的个数。
本文探讨了在排序数组中统计特定数字出现次数的三种高效算法。第一种使用一次二分查找定位目标数字,随后在左右两侧进行顺序扫描。第二种采用两次二分查找,分别定位目标数字的第一个和最后一个实例。第三种适用于整数数组,利用二分查找确定目标数字与相邻浮点数之间的插入位置,从而计算其频率。
1万+

被折叠的 条评论
为什么被折叠?



