数组题——数字在排序数组种出现的次数(sort,equal_range,二分法)

数字在排序数组种出现的次数

先修知识点

  1. 范围for循环:for(元素类型 元素对象:容器对象){  循环体;  } 。用元素对象依次结合容器对象中的每一个元素,每结合一个元素,执行依次循环体,直至容器内的所有元素都被结合完为止。因此可以直接使用元素对象来进行比较判断
  2. equal_range函数:返回两个数first、second。first为value可插入的第一个位置,second则是在不破坏次序的前提下,value可插入的最后一个位置。equal_range(data.begin(),data.end(),k);使用时要注意是equal_range(迭代器开始,迭代器最后,比较值)
  3. sort(begin, end, cmp),其中begin为指向待sort()的数组的第一个元素的指针,end为指向待sort()的数组的最后一个元素的下一个位置的指针,cmp参数为排序准则,如果没有的话,默认以非降序排序。int cmp(int x, int y) { return x > y; } sort(a, a + 2, cmp)。sort(a ,a + len, greater<int>()); //内置类型的由大到小排序。sort(a, a + len, less<int>()); //内置类型的由小到大排序。
  4. lower_bound( )和upper_bound( )函数:lower_bound( )是从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。upper_bound( )从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。lower_bound(begin,end,num)upper_bound(begin,end,num)
  5. lower_bound( begin,end,num,greater<type>() )和upper_bound( begin,end,num,greater<type>() )是重载函数,分别是在从大到小的数组中查找一个小于等于和第一个小于的地址。

题目描述

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

解题思路

最简单的思路:循环size次,与该数字比较,相同+1。 使用范围for循环:利用元素对象a来对比

class Solution {
public:
    int GetNumberOfK(vector<int> data ,int k) 
    {
        int i=0;
        for(auto a:data)
        {
            if(a==k) 
                i++;
        }
        return i;
    }
};

使用equal_range函数是排序数组中查找与比较值相等的数的范围。也可以用lower_bound()以及upper_bound()来确定范围。

class Solution {
public:
    int GetNumberOfK(vector<int> data ,int k) 
    {
        int a=0;
        /*
        auto r=equal_range(data.begin(),data.end(),k);
        return a=r.second-r.first;
        */
        auto l=lower_bound(data.begin(),data.end(),k);
        auto r=upper_bound(data.begin(),data.end(),k);
        return a=r-l;
    }
};

学习了一下二分法,使用迭代器(l=data.begin,r=data.end,m=l+(r-l)/2)     [注:用(l+r)/2可能会超出内存]     以及循环(while(r>=l))来建立二分查找,找到该数值所在位置。  找到之后,通过在其左右区间内循环,计算其出现次数。

特别的要注意:因为循环条件是r>=l,所以一定要先判断data是否为空,否则while一直死循环下去。

class Solution {
public:
    int GetNumberOfK(vector<int> data ,int k) 
    {
        int t;
        if(!data.size()) return 0;
        auto l=data.begin(),r=data.end()-1;
        auto m=l+(r-l)/2;
        while(r>=l)
        {
            if(*m==k) break;
            if(*m>k) r=m-1;
            if(*m<k) l=m+1;
            m=l+(r-l)/2;
        }
        for(auto i=m;i>=l;i--)
        {
            if(*i==k) 
                t++;
            else
                break;
        }
        for(auto i=m+1;i<=r;i++)
        {
            if(*i==k) 
                t++;
            else
                break;
        }
        return t;
    }
};

特别注意:两个for循环如果都用的是i=m,会多算一次m=k,此时不能在最后return t-1,因为如果0的话会变成-1.因此在程序中第二个for循环使用i=m+1。

用到的二分法就是:(用例找一个数的位置)

class Solution{
public:
    int search(vector<int>& nums,int target)
    {
        int a;
        if(!nums.size()) return -1;
        auto l=nums.begin(),r=nums.end();
        auto m=l+(r-l)/2;
        while(r>=l)
        {
            if(*m==target) return a=m-nums.begin();
            if(*m>target) r=m-1;
            if(*m<target) l=m+1;
            m=l+(r-l)/2;
        }
        return -1;
    }
};

二分法实现最重要的是 区间的重新选择划分,当左区间时用:r=m-1;右区间时用:r=m+1。否则就会超时

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值