为了方便自己和大家共同学习,本人整理了一些基本解法和比较巧妙的解法~
代码整理自牛客网讨论区:https://www.nowcoder.com/questionTerminal/70610bf967994b22bb1c26f9ae901fa2?f=discussion
剑指offer题型分类及各题的代码及解题思路
题目描述
统计一个数字在排序数组中出现的次数。
分析:
数组有序,可以用二分查找,但是没必要遍历数组,可以找到这个数字第一个出现的数组下标和最后一个数组出现的数组下标,然后再计算出现的次数。
基于这种思想,我们可以写出递归的代码扎到排序数组的第一个k和最后一个k。
方法一:自己写二分查找
C++实现代码如下:
// 计算数字出现的次数
int GetNumberOfK(vector<int> data ,int k)
{
if(data.size() < 1)
{
return 0;
}
int left = leftLimit(data, k, 0, data.size());
int right = rightLimit(data, k, -1, data.size() - 1);
// 找到k在数组中的第一个和最后一个位置,然后相减+1就是个数
return (right - left + 1);
}
// 右边界
int rightLimit(vector<int> data, int k, int left, int right)
{
while(left < right)
{
int mid = (left + right + 1) >> 1;
if(data[mid] <= k)
{
left = mid;
}
else
{
right = mid - 1;
}
}
return right;
}
// 左边界
int leftLimit(vector<int> data, int k, int left, int right)
{
while(left < right)
{
int mid = (left + right) >> 1;
if(data[mid] >= k)
{
right = mid;
}
else
{
left = mid + 1;
}
}
return left;
}
方法二:利用C++ stl的二分查找(
STL equal_range()的用法)
int GetNumberOfK(vector<int> data ,int k)
{
auto resultPair = equal_range(data.begin(), data.end(),k);
return resultPair.second - resultPair.first;
}
方法三:因为data中都是整数,所以可以稍微变一下,不是搜索k的初始和最后出现的位置,而是搜索k-0.5和k+0.5这两个数应该插入的位置,然后相减即可。
int GetNumberOfK(vector<int> data ,int k)
{
int start = biSearch(data, k-0.5); //数字第一次出现的数组下标
int end = biSearch(data, k+0.5); //数字最后一次出现的后面一个数字的下标
return end - start;
}
int biSearch(const vector<int> & data, double num)
{
int s = 0, e = data.size()-1; //s为二分查找数组的第一个数字下标,e为最后一个数字的下标
while(s <= e)
{
int mid = (e - s)/2 + s; //中间数字的下标
if(data[mid] < num) //s右移,往右查找
s = mid + 1;
else if(data[mid] > num) //e往左移,往左查找
e = mid - 1;
}
return s;
}