• 【剑指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)。

  • 相关阅读:
    【微信开发之问题集锦】redirect_uri 参数错误
    调度算法之时间片轮转算法
    快速排序算法分析和实现
    单链表(c语言实现)贼详细
    调度算法之最短作业优先算法
    HDU1027
    HDU1753 (大正小数相加)
    HDU 1715 (大数相加,斐波拉契数列)
    HDU 1316 (斐波那契数列,大数相加,大数比较大小)
    HDU1047(多个大数相加)
  • 原文地址:https://www.cnblogs.com/flix/p/12518720.html
Copyright © 2020-2023  润新知