[剑指offer]-在排序数组中查找数字

题目描述

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

思路1:直接用二分法找出要找的数字K,然后通过两个while()循环,分别朝前和后扫描,得到K的个数; 但是当K的个数较多时,前后扫描相当于顺序查找,时间复杂度仍然很高。

思路2:用二分法,采用递归的方式,分别找到第一个K的下标和,最后一个K的下标,然后根据两个下标的差得出K的个数,代码如下:

class Solution {
public:
    int GetNumberOfK(vector<int> data ,int k) {
        int count =0;
        if(data.size() <=0)
            return 0;
        int first = getFirstK(data,k,0,data.size()-1);
        int last = getLastK(data,k,0,data.size()-1);
        if(first==-1 || last==-1)
            return 0;
        return last-first+1;
    }
    int getFirstK(vector<int> data,int k,int start,int end){
        if (start > end)
            return -1;     //数组中不包含数字,返回-1
        int mid = (start+end)>>1;
        if(data[mid]==k){
            if((mid>0 && data[mid-1] != k)||mid==0)
                return mid;
            else
                end = mid - 1;
        }
        else if(data[mid]>k)
            end = mid-1;
        else
            start = mid+1;
        return getFirstK(data,k,start,end);
    }
    int getLastK(vector<int> data,int k,int start,int end){
        if (start > end)
            return -1;    //数组中不包含数字,返回-1
        int mid = (start+end)>>1;
        if(data[mid]==k){
            if((mid < data.size()-1 && data[mid+1] != k)||mid==data.size()-1)
                return mid;
            else
                start = mid + 1;
        }
        else if(data[mid]>k)
            end = mid-1;
        else
            start = mid+1;
        return getLastK(data,k,start,end);
    }
};

思路3:和思路二类似,不采用递归的方式,直接用二分法,注意易错点!!!

class Solution {
public:
    int GetNumberOfK(vector<int> data ,int k) {
        if(data.size() == 0)
            return 0;
        int left = firstk(data,k);
        int right = lastk(data,k);
        if(left == -1 || right == -1)
            return 0;
        return right-left+1;
    }
    int firstk(vector<int> data,int k){
        int left = 0;
        int right = data.size()-1;
        int mid = (left+right)/2;
        while(left <= right){
            if(data[mid] == k){
                if((mid-1>=left && data[mid-1]!= k) || mid==left)
                    return mid;
//!!!!犯错处,当mid位和mid-1位均等于k,取right=mid-1,不然可能出现死循环。
                right = mid-1;
            }
            else if(data[mid] <k)
                left = mid+1;
            else
                right = mid-1;
            mid = (left+right)/2;
        }
        return -1;
    }
    int lastk(vector<int> data,int k){
        int left = 0;
        int right = data.size()-1;
        int mid = (left+right)/2;
        while(left <= right){
            if(data[mid] == k){
                if((mid+1<=right && data[mid+1]!=k) || mid==right)
                    return mid;
//!!!!犯错处,当mid位和mid+1位均等于k,取left=mid+1,不然可能出现死循环。
                left = mid+1;  
            }
            else if(data[mid] <k)
                left = mid+1;
            else
                right = mid-1;
            mid = (left+right)/2;
        }
        return -1;
    }
};

 思路四:(最优思路)

由于data中都是整数,所以可以稍微变一下,不是搜索k的两个位置,而是搜索k-0.5和k+0.5

//这两个数应该插入的位置,然后相减即可。

class Solution {
public:
    int GetNumberOfK(vector<int> data ,int k) {
        return biSearch(data, k+0.5) - biSearch(data, k-0.5) ;
    }
private:
    int biSearch(const vector<int> & data, double num){
        int s = 0, e = data.size()-1;     
        while(s <= e){
            int mid = (e - s)/2 + s;
            if(data[mid] < num)
                s = mid + 1;
            else if(data[mid] > num)
                e = mid - 1;
        }
        return s;
    }
};

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值