【剑指Offer-知识迁移能力】面试题53:在排序数组中查找数字

题目描述

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

思路1

直接遍历数组一遍,统计出现的次数,时间复杂度为O(logn)。代码如下:

class Solution {
public:
    int GetNumberOfK(vector<int> data ,int k) {
        if(data.empty())
            return 0;
        
        int ans = 0;
        for(int i=0; i<data.size(); i++){
            if(data[i]==k)
                ans++;
        }
        return ans;
    }
};

思路2

思路1没有用到“数组是排序的”这个条件。因为数组是排序的,我们可以使用二分查找来找到第一个k的下标firstk和最后一个k的下标lastk,k出现的次数就是lastk-firstk+1. 以找第一个k的下标为例,首先使用二分查找在范围[left, right]找到中间数字,如果中间数字data[mid]等于k,并且data[mid]-1不等于k,则说明mid就是第一个k的下标,否则则说明当前k的左边还有k,则缩小查找范围至[left, mid-1];如果中间数字大于k,则说明k在中间数字的左边,则缩小范围至[left, mid-1],如果中间数字小于k,则说明k在右边,则缩小范围至[mid+1, left],如果找不到则返回-1。可以用类似的方法查找最后一个k的下标,代码如下:

class Solution {
public:
    
    int getFirstk(vector<int> data, int left, int right, int k){
        if(left>right)
            return -1;
        
        int mid = (left+right)/2;
        if(data[mid]==k){
            if(mid==0||(mid>0 && data[mid-1]!=k))
                return mid;
            else right=mid-1;
        }else if(data[mid]>k){
            right=mid-1;
        }else if(data[mid]<k){
            left=mid+1;
        }
        return getFirstk(data, left, right, k);
    }
    
    int getLastk(vector<int> data, int left, int right, int k){
        if(left>right)
            return -1;
        
        int mid = (left+right)/2;
        if(data[mid]==k){
            if(mid==data.size()-1 || (mid<data.size()-1 && data[mid+1]!=k))
                return mid;
            else left=mid+1;
        }else if(data[mid]>k){
            right=mid-1;
        }else if(data[mid]<k){
            left=mid+1;
        }
        return getLastk(data, left, right, k);
    }
    
    int GetNumberOfK(vector<int> data ,int k) {
        if(data.empty())
            return 0;
        
        int firstk = getFirstk(data, 0, data.size()-1, k);
        int lastk = getLastk(data, 0, data.size()-1, k);
        if(firstk>-1&&lastk>-1)
            return lastk-firstk+1;
        else return 0;
    }
};

由于二分查找的时间复杂度为O(logn),所以该算法的时间复杂度为O(logn)。

posted @ 2020-03-18 17:26  Flix  阅读(154)  评论(0编辑  收藏  举报