刷题:牛客JZ53 数字在升序数组中出现的次数

145 阅读2分钟

网址: www.nowcoder.com/practice/70…

描述

给定一个长度为 n 的非降序数组和一个非负数整数 k ,要求统计 k 在数组中出现的次数

数据范围:0 \le n \le 1000 , 0 \le k \le 1000≤n≤1000,0≤k≤100,数组中每个元素的值满足 0 \le val \le 1000≤val≤100
要求:空间复杂度 O(1)O(1),时间复杂度 O(logn)O(logn)

public:
    int GetNumberOfK(vector<int> data ,int k) {
        int l=data.size();
        int left=0;   //左界
        int right=l-1;   //右界
        int f=(left+right)/2;   //判断中项
        int ans=0;
        for(;right>=left;)   //要始终保证左界小于右界,可以相等
        {
            
            if(data[f]>=k && (f==0 || data[f-1]<k))   //找到第一个大于等于k的数
            {
                if(data[f]==k)   //如果相等就说明存在,开始打印后续数字
                {
                    for(int i=f;data[i]==k;i++)
                    {
                        ans++;
                    }
                    return ans;
                }
                else return 0;   //否则说明不存在次数
            }
            else if(data[f]>=k)  
            {
                right=f-1;   //大了,就把中项-1作为右界,范围变成[left,f-1]
                f=(left+right)/2;   
            }
            else {
                left=f+1;   //小了,就把中项+1作为左界,范围变成[f+1,right]
                f=(left+right)/2;
            }
        }
        return 0;
    }
};

总结:

利用二分法,主要是确定好范围,左右界都是闭区间,每次的数字[i]不符合要查找的数时,说明[i]这个数字不合格,可以排除,就将f进行+1或者-1作为左界或者右界。循环的判断条件是始终保持左界在右界的左面,或者重合。

函数:

c++中有利用[二分查找]的方法在一个排好序的数组中进行查找的函数:lower_bound( )和upper_bound( ),函数定义在<algorithm>头文件中。

lower_bound( begin,end,num):从数组的begin位置到end-1位置之间,二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end地址。用返回的地址减去起始地址begin,可以得到找到的数字在数组中的下标。

upper_bound( begin,end,num):从数组的begin位置到end-1位置,二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end地址。用返回的地址减去起始地址begin,可以得到找到的数字在数组中的下标。

在此题中的运用:

return upper_bound(nums.begin(), nums.end(), target) - lower_bound(nums.begin(), nums.end(), target);

拓展:

在从大到小的排序数组中,重载lower_bound()和upper_bound():

lower_bound( begin,end,num,greater() ):从数组的begin位置到end-1位置二分查找第一个小于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

upper_bound( begin,end,num,greater() ):从数组的begin位置到end-1位置二分查找第一个小于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。