剑指offer(C++)-JZ53:数字在升序数组中出现的次数(算法-搜索算法)

简介: 剑指offer(C++)-JZ53:数字在升序数组中出现的次数(算法-搜索算法)

题目描述:

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

数据范围:0≤n≤1000,0≤k≤100,数组中每个元素的值满足 0≤val≤100

要求:空间复杂度 O(1),时间复杂度 O(logn)

示例:

输入:

[1,2,3,3,3,3,4,5],3


返回值:

4

解题思路:

本题考察算法-搜索算法的使用。考虑到复杂度的要求,采用二分法的思路解题。具体实现列了三种写法:


解法一:二分查找


  1. 因题目中全是整数,此时可以将k加减一个小数,达到错位的目的。
  2. BinarySearch(data, k + 0.1)得到的是目标值最后一次出现位置的右侧,BinarySearch(data, k - 0.1)得到的是目标值首次出现的位置,相减刚好是出现的次数。
  3. BinarySearch函数执行二分查找,当左边界超过了右边界,说明此时的左边界是目标值的位置向上取整。

解法二:STL内置二分搜索算法-equal_range


  1. result是一个pair,里面存放了两个迭代器。
  2. first表示k首次出现的位置,second表示k最后一个出现位置的下一个位置。

解法三:模拟STL内置函数-lower_bound&upper_bound


  1. lower_bound寻找该值首次出现的位置。
  2. upper_bound寻找该值最后一次出现的位置,返回该位置的后一位。

测试代码:

解法一:二分查找

class Solution {
public:
    // 二分查找
    int BinarySearch(vector<int>& data, float k)
    { 
        int left = 0;
        int right = data.size() - 1;
        // 确定目标的左右边界
        // 当左边界超过了右边界,说明此时的左边界是目标值的位置向上取整
        while(left <= right)
        { 
            int mid = (left + right) / 2;
            if(data[mid] < k)
                left = mid + 1;
            else if(data[mid] > k)
                right = mid - 1;
        }
        return left;
    }
    // 寻找目标值
    int GetNumberOfK(vector<int> data ,int k) 
    {
        // 因题目中全是整数,此时可以将k加减一个小数,达到错位的目的
        // BinarySearch(data, k + 0.1)得到的是目标值最后一次出现位置的右侧
        // BinarySearch(data, k - 0.1)得到的是目标值首次出现的位置
        // 相减刚好是出现的次数
        return BinarySearch(data, k + 0.1) - BinarySearch(data, k - 0.1);
    }
};

解法二:equal_range

class Solution {
public:
    // 寻找目标值
    int GetNumberOfK(vector<int> data ,int k) 
    {
        // result是一个pair,里面存放了两个迭代器
        // first表示k首次出现的位置,second表示k最后一个出现位置的下一个位置
        auto result = equal_range(data.begin(), data.end(),k);
        return result.second - result.first;
    }
};

解法三:lower_bound&upper_bound

class Solution {
public:
    // 寻找目标值
    int GetNumberOfK(vector<int> data ,int k) 
    {
        // 寻找该值首次出现的位置
        int first = LowerBound(data, k);
        // 寻找该值最后一次出现的位置,返回该位置的后一位
        int second = UpperBound(data, k);
        return second - first;
    }
    // 寻找该值首次出现的位置
    int LowerBound(vector<int>& data, int k)
    {
        int l = 0, r = data.size();
        while(l<r)
        {
            int m = (l+r)/2;
            if(data[m]>=k)
                r = m;
            else
                l = m+1;
        }
        return l;
    }
    // 寻找该值最后一次出现的位置,返回该位置的后一位
    int UpperBound(vector<int>& data, int k)
    {
        int l = 0, r = data.size();
        while(l<r)
        {
            int m = (l+r)/2;
            if(data[m]>k)
                r = m;
            else
                l = m+1;
        }
        return l;
    }
};


相关文章
|
18小时前
|
存储 算法
【数据结构与算法 | 基础篇】[数组专题]力扣88
【数据结构与算法 | 基础篇】[数组专题]力扣88
|
2天前
|
存储 算法
数据结构与算法②(复杂度相关OJ)(六道数组OJ题)(下)
数据结构与算法②(复杂度相关OJ)(六道数组OJ题)
6 0
|
2天前
|
存储 算法 C语言
数据结构与算法②(复杂度相关OJ)(六道数组OJ题)(上)
数据结构与算法②(复杂度相关OJ)(六道数组OJ题)
20 2
|
5天前
|
算法 搜索推荐 Java
滚雪球学Java(33):数组算法大揭秘:应用案例实战分享
【5月更文挑战第8天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
32 8
滚雪球学Java(33):数组算法大揭秘:应用案例实战分享
|
8天前
|
搜索推荐 算法 Java
滚雪球学Java(29):数组长度和排序算法:让你的程序更高效
【5月更文挑战第4天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
15 0
滚雪球学Java(29):数组长度和排序算法:让你的程序更高效
|
8天前
|
机器学习/深度学习 存储 人工智能
图搜索算法详解
【5月更文挑战第11天】本文介绍了图搜索算法的基础知识,包括深度优先搜索(DFS)、广度优先搜索(BFS)和启发式搜索(如A*算法)。讨论了图搜索中的常见问题、易错点及避免方法,并提供了BFS和A*的Python代码示例。文章强调了正确标记节点、边界条件检查、测试与调试以及选择合适搜索策略的重要性。最后,提到了图搜索在路径规划、游戏AI和网络路由等领域的应用,并概述了性能优化策略。
16 3
|
8天前
|
机器学习/深度学习 存储 算法
数据结构与算法 动态规划(启发式搜索、遗传算法、强化学习待完善)
数据结构与算法 动态规划(启发式搜索、遗传算法、强化学习待完善)
17 1
|
8天前
|
算法 搜索推荐 索引
数据结构与算法 搜索(下)
数据结构与算法 搜索(下)
16 0
|
8天前
|
缓存 算法 搜索推荐
数据结构与算法 搜索(上)
数据结构与算法 搜索(上)
11 1
|
8天前
|
数据采集 存储 算法
数据结构与算法 搜索
数据结构与算法 搜索
9 1