剑指 Offer 53 - I. 在排序数组中查找数字 I

文章介绍了如何在非递减排序数组中统计一个数字出现的次数。提供了两种解决方案:暴力查找(时间复杂度O(n))和二分查找(时间复杂度O(logn))。二分查找方法利用了STL库函数lower_bound和upper_bound,以及自定义二分查找函数,寻找目标数字的边界并计算差值来得出结果。
摘要由CSDN通过智能技术生成

一、题目

题目链接:力扣

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

示例 1:

输入: nums = [5,7,7,8,8,10], target = 8
输出: 2

示例 2:

输入: nums = [5,7,7,8,8,10], target = 6
输出: 0

提示:

0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums 是一个非递减数组
-109 <= target <= 109

二、题解

1、思路

🍊 暴力查找

数大了肯定没二分法快哦。

🍊 二分查找

直观的思路肯定是从前往后遍历一遍。用两个变量记录第一次和最后一次遇见 target 的下标,但这个方法的时间复杂度为 O(n),没有利用到数组升序排列的条件。

大体思路:

很经典的题,两次二分查找x,一次找到x元素最左边位置,一次找到x元素最右边的位置,最终返回的是右边的位置减左边的位置 + 1。当数组大小为零时候特殊处理,返回0。

自定义二分查找函数的算法流程: 

2、代码实现

🍊 暴力查找

class Solution {
public:
    int search(vector<int>& nums, int target) {
        if(nums.size() == 0)return 0;
        int res = 0;
        for(auto& number : nums)
        {
            if(number == target)res++;
        }
        return res;
    }
};

🍊 二分查找

使用C++ STL库函数: lower_bound、 upper_bound。

【C++】从没见过这么详细的lower_bound的讲解_am brother的博客-CSDN博客

  • lower_bound:返回一个非递减序列[first, last)中的第一个大于等于值val的位置;
  • upper_bound:返回一个非递减序列[first, last)中第一个大于val的位置。
class Solution {
public:
    int search(vector<int>& nums, int target) {
        // 查找非递减序列nums中第一个大于target - 1的位置
        int left = upper_bound(nums.begin(), nums.end(), target - 1) - nums.begin();
        // 查找非递减序列nums中第一个大于target的位置
        int right = upper_bound(nums.begin(), nums.end(), target) - nums.begin();
        return right - left;
    }
};

看不懂二分法?看这里,一文搞懂二分查找!二分法(数组中无重复数字、包含重复数字两种情况)_Kashine的博客-CSDN博客 

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int n = nums.size();
        if(n == 0)return 0;
        int left = binary_research(nums, 0, n-1, target);
        int right = binary_research2(nums, 0, n - 1, target);
        if(left == -1)return 0;
        if(right == -1)return  n - left;
        else return right - left;
        return -1;
    }

    // 大于等于target的第一个数字下标
    int binary_research(vector<int>& nums, int i, int j, int target)
    {
        if(nums.size() == 0)return 0;
        int res = -1;
        while(i <= j)
        {
            int mid = i + (j-i)/2;
            if(nums[mid] >= target)
            {
                j = mid - 1;
                res = mid;
            }
            else
            {
                i = mid +1;
            }
        }
        return res;
    }
    // 大于target的第一个数字下标
    int binary_research2(vector<int>& nums, int i, int j, int target)
    {
        if(nums.size() == 0)return 0;
        int res = -1;
        while(i <= j)
        {
            int mid = i + (j-i)/2;
            if(nums[mid] > target)
            {
                j = mid - 1;
                res = mid;
            }
            else
            {
                i = mid +1;
            }
        }
        return res;
    }
};

3、复杂度分析

🍊 暴力查找

时间复杂度:O(n);

空间复杂度:O(1)。

🍊 二分查找

时间复杂度:O(logn);(以2为底)

空间复杂度:O(1)。

4、运行结果

🍊 暴力查找

 🍊 二分查找

STL函数版本:

自定义函数版本:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kashine

你的鼓励将是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值