题目一:数字在排序数组中出现的次数
【统计一个数字在排序数组中出现的次数。如 {1,2,3,3,3,3,4}和数字3,由于3出现的4,所以输出4】
方法一:直接遍历
1、分析
直接遍历数组,由于数组已经排好序了,所以当数组中出现了数字 k 时就开始统计其出现的次数。该方法的时间复杂度为
O
(
n
)
O(n)
O(n) ,还有更快的二分法。
2、代码
class Solution {
public:
int GetNumberOfK(vector<int> data ,int k) {
int len=data.size();
if(len<=0 || k<data[0] || k>data[len-1])
return 0;
int count=0;
vector<int>::const_iterator it=data.begin();
while(it!=data.end())
{
if((*it)==k)
++count;
it++;
}
return count;
}
};
方法二:改进的二分查找
1、分析
使用二分查找的改进方法:待查找数字为 k
- 当数组中间的数字大于 k 时,则 k 位于前半段
- 当数组中间的数字小于 k 时,则 k 位于后半段
- 当数组中间的数字等于 k 时,需要继续查出前半段中 k 的起始位置,后半段中 k 的结束位置。该方法的时间复杂度为 O ( l o g n ) O(logn) O(logn)
- 该方法有递归和非递归的两种实现方式
2、代码
- 递归的方式
/*
* 使用递归的方式
*/
class Solution {
public:
int GetNumberOfK(vector<int> data ,int k) {
if(data.empty())
return 0;
int firstIndex=GetFirstIndex(data,k,0,data.size()-1);
int lastIndex=GetLastIndex(data,k,0,data.size()-1);
int count=0;
if(firstIndex>-1 && lastIndex>-1)
count=lastIndex-firstIndex+1;
return count;
}
// 寻找第第一个k的下标
int GetFirstIndex(vector<int> &data,int k,int start,int end)
{
if(start>end)
return -1;
int mid=start+(end-start)/2;
if(data[mid]==k)
{
if((mid>start && data[mid-1]!=k) || mid==start)
return mid;
else
end=mid-1;
}
else if(data[mid]>k)
{
end=mid-1;
}
else
start=mid+1;
return GetFirstIndex(data,k,start,end);
}
// 寻找第二个k的下标
int GetLastIndex(vector<int> &data,int k,int start,int end)
{
if(start>end)
return -1;
int mid=start+(end-start)/2;
if(data[mid]==k)
{
if((mid<end && data[mid+1]!=k) || mid==end)
return mid;
else
start=mid+1;
}
else if(data[mid]>k)
{
end=mid-1;
}
else
start=mid+1;
return GetLastIndex(data,k,start,end);
}
};
- 非递归的方式
class Solution {
public:
int GetNumberOfK(vector<int> data ,int k) {
if(data.empty())
return 0;
int firstIndex=GetFirstIndex(data,k,0,data.size()-1);
int lastIndex=GetLastIndex(data,k,0,data.size()-1);
int count=0;
if(firstIndex>-1 && lastIndex>-1)
count=lastIndex-firstIndex+1;
return count;
}
// 寻找第第一个k的下标
int GetFirstIndex(vector<int> &data,int k,int start,int end)
{
//初始中间位置,必须放在循环之外
int mid=start+(end-start)/2;
// 循环条件不可漏掉 start=end 的情况
while(start<=end)
{
if(data[mid]>k)
{
end=mid-1;
}
else if(data[mid]<k)
{
start=mid+1;
}
else
{
if((mid>start && data[mid-1]!=k)||mid==start)
{
return mid;
}
else
{
end=mid-1;
}
}
mid=start+(end-start)/2; //更新中间的位置
}
return -1;
}
// 寻找第二个k的下标
int GetLastIndex(vector<int> &data,int k,int start,int end)
{
int mid=start+(end-start)/2;
while(start<=end)
{
if(data[mid]>k)
{
end=mid-1;
}
else if(data[mid]<k)
{
start=mid+1;
}
else
{
if((mid<end && data[mid+1]!=k)||mid==end)
{
return mid;
}
else
{
start=mid+1;
}
}
mid=start+(end-start)/2;
}
return -1;
}
};
方法三:使用STL中的mutiple容器
class Solution {
public:
int GetNumberOfK(vector<int> data ,int k) {
if(data.empty())
return 0;
multiset<int> mp;
for(auto &i:data)
{
mp.insert(i);
}
return mp.count(k);
}
};