【算法】双指针+二分(C/C++

简介: 【算法】双指针+二分(C/C++

二分简述:

二分算法,又称为二分搜索或折半搜索,是一种在有序数组中查找特定元素的搜索算法。其基本思想是将数组分成两半,然后根据目标值与中间元素的大小关系来决定是继续在左侧还是右侧进行搜索。这个过程会不断重复,直到找到目标值或搜索范围为空为止。

下面是二分算法的一般步骤:

1. 初始化:设置两个指针,一个指向数组的起始位置(low),另一个指向数组的结束位置(high)。此时,low = 0,high = 数组长度 - 1或者low = 1,high = 数组长度 。


2. 循环条件:只要low小于等于high,就继续循环。


3. 计算中间位置:在每次循环中,计算中间位置mid=(low + high) / 2。


4. 比较:比较中间元素与目标值。

  - 如果中间元素等于目标值,搜索成功,返回mid。

  - 如果中间元素大于目标值,说明目标值在数组的左侧,更新high为mid - 1。

  - 如果中间元素小于目标值,说明目标值在数组的右侧,更新low为mid + 1。


5. 循环结束:如果low大于high,说明没有找到目标值,搜索失败。

二分算法的时间复杂度是O(log n),其中n是数组的长度。这使得它在大规模数据搜索中非常高效。然而,二分搜索的一个前提条件是数组必须是有序的。

二分算法不仅可以用于搜索,还可以用于解决一些优化问题,如找到函数的最大值或最小值等。


双指针简述:

双指针是编程中常用的一种技术,特别是在处理数组和字符串问题时。双指针方法通常涉及在数据结构中使用两个指针来遍历和解决问题。双指针技术可以用于多种算法问题,如查找、排序、搜索子数组或子字符串等。

常见的双指针应用场景:

  1. 滑动窗口
  • 用于解决连续子数组或子字符串的问题,如最长无重复字符的子串。
  • 两个指针定义了一个窗口,随着遍历的进行,窗口的大小和位置会改变。
  1. 快慢指针(Floyd's Tortoise and Hare Algorithm):
  • 用于检测链表是否有环。
  • 一个指针移动速度是另一个的两倍,如果链表有环,它们最终会相遇。
  1. 两数之和
  • 给定一个数组,找出数组中两个数的和等于特定值。
  • 通过一个指针固定一个数,另一个指针遍历数组找到另一个数。
  1. 反转字符串或链表
  • 使用两个指针分别指向字符串或链表的头部和尾部,逐步交换两指针指向的元素。
  1. 归并排序
  • 两个指针分别指向已排序的两个子数组,逐步比较并合并。
  1. 寻找旋转排序数组中的最小值
  • 数组是旋转过的有序数组,使用两个指针找到最小值。


题目链接:3745. 牛的学术圈 I - AcWing题库

由于对计算机科学的热爱,以及有朝一日成为 「Bessie 博士」的诱惑,奶牛 Bessie 开始攻读计算机科学博士学位。


经过一段时间的学术研究,她已经发表了 N篇论文,并且她的第 i篇论文得到了来自其他研究文献的 ci次引用。


Bessie 听说学术成就可以用 ℎ 指数来衡量。


ℎ 指数等于使得研究员有至少 ℎ 篇引用次数不少于 ℎ 的论文的最大整数 ℎ。


例如,如果一名研究员有 4 篇论文,引用次数分别为 (1,100,2,3),则 ℎ 指数为 2,然而若引用次数为 (1,100,3,3) 则 hℎ 指数将会是 3。


为了提升她的 ℎ 指数,Bessie 计划写一篇综述,并引用一些她曾经写过的论文。


由于页数限制,她至多可以在这篇综述中引用 L 篇论文,并且她只能引用每篇她的论文至多一次。


请帮助 Bessie 求出在写完这篇综述后她可以达到的最大 ℎ 指数。


注意 Bessie 的导师可能会告知她纯粹为了提升 ℎ 指数而写综述存在违反学术道德的嫌疑;我们不建议其他学者模仿 Bessie 的行为。


输入格式


输入的第一行包含 N 和 L。


第二行包含 N个空格分隔的整数 c1,…,cN。


输出格式


输出写完综述后 Bessie 可以达到的最大 ℎ 指数。


数据范围


1≤N≤10^5

0≤ci≤10^5

0≤L≤10^5


输入样例1:

4 0
1 100 2 3

输出样例1:

2

样例1解释

Bessie 不能引用任何她曾经写过的论文。上文中提到,(1,100,2,3) 的 ℎ 指数为 22。

输入样例2:

4 1
1 100 2 3

输出样例2:

3

样例2解释:

如果 Bessie 引用她的第三篇论文,引用数会变为(1,100,3,3)。上文中提到,这一引用数的 ℎ 指数为 3。

题目分析:

此题要求h指数,他可以引用自己的论文增加自己的h指数,最多引用一次,引用一篇则对应的一篇引用加1,所以分界线就在c[i]>=h与c[i]=h-1这里,其他的情况不用管。当c[i]>=h时,无论如何引用都已经大于h了,若想增加就在c[i]=h-1这里,引用一次对应加1,刚好到h,对于c[i]<h-1的无论如何加1都到不了h。我们可以二分查找h指数,当h符合条件,区间给到右区间,寻找有没有更大的选择。

代码实现

二分:
#include<iostream>
using namespace std;
int n,l;
int c[100005];
bool cheak(int mid){//判断此时mid是否符合h指数的条件
  int a=0;
  int b=0;
  for(int i=1;i<=n;i++){
    if(c[i]>=mid){//统计大于等于h的个数
      a++;
    }
    if(c[i]==mid-1){//统计刚好引用一次到h的个数
      b++;
    }
  }
  return a+min(b,l)>=mid;//a+min(b,l)为最终的h
}
int main(){
  cin>>n>>l;
  for(int i=1;i<=n;i++){
    cin>>c[i];
  }
  int l=0,r=n;
  while(l<r){
    int mid=l+r+1>>1;
    if(cheak(mid)){
      l=mid;
    }else{
      r=mid-1;
    }
  }
  cout<<r<<endl;
  return 0;
}
双指针:
#include <bits/stdc++.h>
#define int long long 
 
using namespace std;
 
const int N = 2e5 + 10;
 
int main() 
{
    int n, k;
    cin >> n >> k;
    int a[N]; // 存取每个数的个数
    int ma = 0;
    for(int i = 1; i <= n; i ++ ) {
        int x;
        cin >> x; 
        a[x] ++ ;
        ma = max(ma, x); // 记录最大值
    }
 
    int res = 0; // 最终结果
    int sum = n; // 初始化,目前大于0的个数肯定是所有数量
    int j = 0;
    for(int i = 0; i <= ma + 5; i ++ ) {
        while(sum >= j && i >= j) { // 双指针的重点,个数要比j多,i要比j大
            res = max(res, j); // 成立,h指数可以为j
            j ++ ;
        }
        sum -= a[i]; 
        if(sum + min(a[i], k) >= j && i >= j - 1 && k != 0) res = max(res, j); // 处理k
 
    }
    cout << res << endl;
    return 0;
}

二分与双指针算法都可以解决此题,看个人喜欢哪一种算法了,如果二分写的很好,记得很熟悉,可以使用二分,有的人感觉双指针好理解,关键在于个人喜好,解决题目的算法有很多种,但是只要能把题目A掉就是好算法。


笔者水平有限,代码写的一般,若有错误,请大家指正,一起进步。执笔至此,感触彼多,全文将至,落笔为终,感谢大家的支持。

相关文章
|
存储 监控 算法
基于 C++ 哈希表算法实现局域网监控电脑屏幕的数据加速机制研究
企业网络安全与办公管理需求日益复杂的学术语境下,局域网监控电脑屏幕作为保障信息安全、规范员工操作的重要手段,已然成为网络安全领域的关键研究对象。其作用类似网络空间中的 “电子眼”,实时捕获每台电脑屏幕上的操作动态。然而,面对海量监控数据,实现高效数据存储与快速检索,已成为提升监控系统性能的核心挑战。本文聚焦于 C++ 语言中的哈希表算法,深入探究其如何成为局域网监控电脑屏幕数据处理的 “加速引擎”,并通过详尽的代码示例,展现其强大功能与应用价值。
250 2
|
存储 负载均衡 算法
基于 C++ 语言的迪杰斯特拉算法在局域网计算机管理中的应用剖析
在局域网计算机管理中,迪杰斯特拉算法用于优化网络路径、分配资源和定位故障节点,确保高效稳定的网络环境。该算法通过计算最短路径,提升数据传输速率与稳定性,实现负载均衡并快速排除故障。C++代码示例展示了其在网络模拟中的应用,为企业信息化建设提供有力支持。
391 15
|
8月前
|
存储 算法
算法入门:专题一:双指针(有效三角形的个数)
给定一个数组,找出能组成三角形的三元组个数。利用“两边之和大于第三边”的性质,先排序,再用双指针优化。固定最大边,左右指针从区间两端向内移动,若两短边之和大于最长边,则中间所有组合均有效,时间复杂度由暴力的O(n³)降至O(n²)。
|
存储 算法 数据处理
公司局域网管理中的哈希表查找优化 C++ 算法探究
在数字化办公环境中,公司局域网管理至关重要。哈希表作为一种高效的数据结构,通过哈希函数将关键值(如IP地址、账号)映射到数组索引,实现快速的插入、删除与查找操作。例如,在员工登录验证和设备信息管理中,哈希表能显著提升效率,避免传统线性查找的低效问题。本文以C++为例,展示了哈希表在局域网管理中的具体应用,包括设备MAC地址与IP分配的存储与查询,并探讨了优化哈希函数和扩容策略,确保网络管理高效准确。
|
监控 算法 数据处理
基于 C++ 的 KD 树算法在监控局域网屏幕中的理论剖析与工程实践研究
本文探讨了KD树在局域网屏幕监控中的应用,通过C++实现其构建与查询功能,显著提升多维数据处理效率。KD树作为一种二叉空间划分结构,适用于屏幕图像特征匹配、异常画面检测及数据压缩传输优化等场景。相比传统方法,基于KD树的方案检索效率提升2-3个数量级,但高维数据退化和动态更新等问题仍需进一步研究。未来可通过融合其他数据结构、引入深度学习及开发增量式更新算法等方式优化性能。
309 17
|
11月前
|
存储 监控 算法
基于跳表数据结构的企业局域网监控异常连接实时检测 C++ 算法研究
跳表(Skip List)是一种基于概率的数据结构,适用于企业局域网监控中海量连接记录的高效处理。其通过多层索引机制实现快速查找、插入和删除操作,时间复杂度为 $O(\log n)$,优于链表和平衡树。跳表在异常连接识别、黑名单管理和历史记录溯源等场景中表现出色,具备实现简单、支持范围查询等优势,是企业网络监控中动态数据管理的理想选择。
273 0
|
机器学习/深度学习 存储 算法
基于 C++ 布隆过滤器算法的局域网上网行为控制:URL 访问过滤的高效实现研究
本文探讨了一种基于布隆过滤器的局域网上网行为控制方法,旨在解决传统黑白名单机制在处理海量URL数据时存储与查询效率低的问题。通过C++实现URL访问过滤功能,实验表明该方法可将内存占用降至传统方案的八分之一,查询速度提升约40%,假阳性率可控。研究为优化企业网络管理提供了新思路,并提出结合机器学习、改进哈希函数及分布式协同等未来优化方向。
336 0
|
存储 监控 算法
基于 C++ 哈希表算法的局域网如何监控电脑技术解析
当代数字化办公与生活环境中,局域网的广泛应用极大地提升了信息交互的效率与便捷性。然而,出于网络安全管理、资源合理分配以及合规性要求等多方面的考量,对局域网内计算机进行有效监控成为一项至关重要的任务。实现局域网内计算机监控,涉及多种数据结构与算法的运用。本文聚焦于 C++ 编程语言中的哈希表算法,深入探讨其在局域网计算机监控场景中的应用,并通过详尽的代码示例进行阐释。
280 4
|
存储 算法 安全
企业员工数据泄露防范策略:基于 C++ 语言的布隆过滤器算法剖析[如何防止员工泄密]
企业运营过程中,防范员工泄密是信息安全领域的核心议题。员工泄密可能致使企业核心数据、商业机密等关键资产的流失,进而给企业造成严重损失。为应对这一挑战,借助恰当的数据结构与算法成为强化信息防护的有效路径。本文专注于 C++ 语言中的布隆过滤器算法,深入探究其在防范员工泄密场景中的应用。
305 8
|
存储 监控 算法
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
在数字化办公时代,公司监控上网软件成为企业管理网络资源和保障信息安全的关键工具。本文深入剖析C++中的链表数据结构及其在该软件中的应用。链表通过节点存储网络访问记录,具备高效插入、删除操作及节省内存的优势,助力企业实时追踪员工上网行为,提升运营效率并降低安全风险。示例代码展示了如何用C++实现链表记录上网行为,并模拟发送至服务器。链表为公司监控上网软件提供了灵活高效的数据管理方式,但实际开发还需考虑安全性、隐私保护等多方面因素。
307 0
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨