【LeetCode & 剑指offer刷题】数组题8:53 数字在排序数组中出现的次数

【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
}
 
 

 

posted @ 2019-01-05 14:07  wikiwen  阅读(598)  评论(0编辑  收藏  举报