【LeetCode & 剑指offer 刷题笔记】目录(持续更新中...)
53 数字在排序数组中出现的次数
题目描述
统计一个数字在排序数组中出现的次数。
//方法一:顺序扫描,统计出现的次数,O(n)
/*
方法二:由于是有序数组,可以用二分查找
用stl中函数
lower_bound 和 upper_bound
O(logn) O(1)
*/
class Solution
{
public:
int GetNumberOfK(vector<int>& data ,int k)
{
if(data.empty()) return 0;
vector<int>::iterator first = lower_bound(data.begin(),data.end(),k); //返回第一个大于等于k的位置
vector<int>::iterator last = upper_bound(data.begin(),data.end(),k); //返回第一个大于k的位置
return last - first;
}
};
/*
方法:自己实现
lower_bound 和 upper_bound
O(logn) O(1)
*/
class Solution
{
public:
int GetNumberOfK(vector<int>& data ,int k)
{
if(data.empty()) return 0;
int first = my_lower_bound(data,k); //返回第一个大于等于k的位置
int last = my_upper_bound(data,k); //返回第一个大于k的位置
return last - first;
}
private:
int my_lower_bound(vector<int>& a, int target)
{
int left = 0, right = a.size(); //与stl中喜欢把end指向末尾后一个元素的做法类似
while (left < right)
{
int mid = left + (right - left) / 2;
if (a[mid] < target)
left = mid + 1;
else //没有单独考虑等于的情况
right = mid;
}
return right;
}
int my_upper_bound(vector<int>& a, int target)
{
int left = 0, right = a.size(); //与stl中喜欢把end指向末尾后一个元素的做法类似
while (left < right)
{
int mid = left + (right - left) / 2;
if (a[mid] <= target)
left = mid + 1;
else
right = mid;
}
return right;
}
};
//方法二:由于是有序的,可以用二分查找,找到该数第一次出现的位置和最后一次出现的位置,计算次数即可
//O(logn)
class Solution
{
public:
int GetNumberOfK(vector<int>& data ,int k)
{
if(data.empty()) return 0;
int first = getFirst(data, k);
int last = getLast(data, k);
if(first != -1 && last != -1) return last - first + 1;
else return 0; //如果找不到就返回0
}
private:
int getFirst(vector<int>& a, int k)
{
int left = 0;
int right = a.size() - 1;
int mid;
while(left <= right)
{
mid = (left+right) / 2;
if(a[mid] < k)
left = mid + 1;
else if(a[mid] > k)
right = mid - 1;
else if(mid-1 >= 0 && a[mid-1] == k)//当前数等于k,前一个数也等于k时,继续在左半区间查找
right = mid - 1;
else //当前数等于k,前一个数不等于k或者为开头时,返回mid
return mid;
}
return -1; //找不到时返回-1
}
int getLast(vector<int>& a, int k)
{
int left = 0;
int right = a.size() - 1;
int mid;
while(left <= right)
{
mid = (left+right) / 2;
if(a[mid] < k)
left = mid + 1;
else if(a[mid] > k)
right = mid - 1;
else if(mid+1 < a.size() && a[mid+1] == k) //当前数等于k,后一个数也等于k时,继续在右半区间查找
left = mid+1;
else //当前数等于k,后一个数不等于k或者后一个数为末尾时,返回mid
return mid;
}
return -1; //找不到时返回-1
}
};
//回顾普通的二分查找
int binarysearch(vector<int>& a, int k)
{
int left = 0;
int right = a.size() - 1;
int mid;
while(left <= right)
{
mid = (left+right) / 2;
if(a[mid] < k) //k较a[mid]大时,在右半区间找
left = mid + 1;
else if(a[mid] > k) //k较小时,在左半区间找
right = mid - 1;
else //若想等则返回mid
return mid;
}
return -1; //找不到时返回-1
}