剑指Offer_面试题38_数字在排序数组中出现的次数

63 篇文章 1 订阅
40 篇文章 0 订阅

题目描述

统计一个数字在排序数组中出现的次数。

分析:遍历一遍数组可以得到结果,时间复杂度O(n),但是这完全没利用排序数组的特性。提到排序数组查找问题就想到二分查找,二分查找O( logn )找到k,但这个k的位置是不确定的,不知道是第几个k,如果能用两次二分查找找到第一个k和最后一个k,就能得到k的个数,并且时间复杂度是O(logN);

非递归:

class Solution {
public:
    int GetNumberOfK(vector<int> data ,int k) {
        int num = 0;
        if(!data.empty()){
            int first = GetFirstK(data, k);
            int last = GetLastK(data, k);
            if(first != -1 && last != -1)
                num = last - first + 1;
        }
        return num;
    }
    
    int GetFirstK(const vector<int> &data, int k)
    {
        int low = 0;
        int high = data.size() -1;
        int mid = 0;
        //二分查找必须是<=
        while(low <= high){
            mid = (low + high) / 2;
            if(data[mid] == k){
                if((mid > 0 && data[mid-1] != k) || mid == 0)
                    return mid;
                else
                    high = mid-1;
            }
            else if(data[mid] > k)
                high = mid - 1;
            else
                low = mid + 1;
        }
        return -1;
    }
    int GetLastK(const vector<int> &data, int k)
    {
        int low = 0;
        int high = data.size() -1;
        int mid = 0;
        //二分查找必须是<=
        while(low <= high){
            mid = (low + high) / 2;
            if(data[mid] == k){
                if((mid < data.size()-1 && data[mid+1] != k) || mid == data.size()-1)
                    return mid;
                else
                    low = mid + 1;
            }
            else if(data[mid] > k)
                high = mid - 1;
            else
                low = mid + 1;
        }
        return -1;
    }
};


递归:

classSolution {
public:
    intGetNumberOfK(vector<int> data ,intk) {
        if(data.empty()) return0;
        intlast = GetLastK(data, k, 0, data.size()-1);
        intfirst = GetFirstK(data, k, 0, data.size()-1);
        if(last == -1|| first == -1)
            return0;
        else
            returnlast - first + 1;
    }
     
    intGetFirstK(constvector<int>& data, intk, intlow, inthigh)
    {
        if(low > high) return-1;
        intmid = (low+high)/2;
        if(data[mid] == k)
        {
            if((mid > 0&& data[mid - 1] != k)
                || mid == 0)
                returnmid;
            else
                high = mid - 1;
        }
        elseif(data[mid] > k)
            high = mid - 1;
        else
            low = mid + 1;
        returnGetFirstK(data, k, low, high);
    }
     
    int GetLastK(constvector<int>& data, intk, intlow, inthigh)
    {
        if(low > high) return-1;
        intmid = (low + high)/2;
        if(data[mid] == k)
        {
            if((mid < data.size() - 1&& data[mid+1] != k)
              || mid == data.size() - 1)
                returnmid;
            else
                low = mid + 1;
        }
        elseif(data[mid] > k)
            high = mid - 1;
        else
            low = mid + 1;
        returnGetLastK(data, k, low, high);
    }
};


这其实是二分查找的变形,类似的有查找第一个大于k的元素,第一个小于等于k的元素等等,总结起来就是:

// 这里必须是 <=
while (left <= right) {
    int mid = (left + right) / 2;
    if (array[mid] ? key) {
        //... right = mid - 1;
    }
    else {
        // ... left = mid + 1;
    }
}
return xxx;





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值