【算法题解】二分查找的经典问题解析

news2024/11/23 20:02:20

在这里插入图片描述

文章目录

  • 什么是二分?
  • 关于二分的一些题目
    • 1.分巧克力
      • 解题思路
      • 编写代码
    • 2.数组中数值和下标相等的元素
    • 3.0到n-1中缺失的数字
    • 4.数列分段 II
      • 解题思路
      • 编写代码
  • 总结

什么是二分?

二分是一种思想,用于有序数组中快速查找目标元素。

用动图展示一下二分查找:
在这里插入图片描述

二分查找的模版很简单,但是很多题目很难想到用二分。

关于二分的一些题目

1.分巧克力

题目描述:
在这里插入图片描述
圈出来的都是重要信息。
这道题的大致意思就是有N个小朋友,现在有K个蛋糕,这K个蛋糕,蛋糕的长和宽都给出,现在要切蛋糕,但是蛋糕必须满足一定条件,保证边长是整数,并且保证切出来的蛋糕都是一样的并且是正方形(输入的蛋糕必须保证每个小朋友都可以分到1*1的蛋糕)。

在这里插入图片描述
用上面的样例举例:

在这里插入图片描述

第一种满足要求的切法:
在这里插入图片描述
如果我们再增加到33就不满足了。
在这里插入图片描述
可以看到增加到3
3后最多可以切4个,已经不满足条件了。
所以这个例子的最大的边长就是2.

解题思路

首先,先看看这道题问的什么,这道题问的是输出可以切出来的正方形的最大边长。
这道题叫我们求边长,他问什么我们就二分什么。
这道题我们就二分边长,这道题已经给出了边长的范围了。
在这里插入图片描述
所以这道题我们应该将边的范围限制在这个范围中间,l就是1,r就是1e5,在这个范围进行二分。
那么区间我们已经划定好了,区间变换的条件是什么呢?
我们假设我们第一次二分,这个数是满足的,如果这个数是满足的,那么答案是在左边还是右边呢?很显然是在右边,因为这道题求的是最大值,如果当前的数满足左边的比当前数小的数肯定都满足,但是最佳答案肯定是当前数,所以左边的数可以不做考虑了,所以下一次二分的区间应该是当前数到r。
那么如果当前数不满足反过来肯定是要缩小范围,所以下一次二分的区间应该是l到当前数。

那么具体条件是什么呢?
题目已经给出了满足的条件了,我们只需要编写一个函数检查一下这个边长是否满足当前条件即可。
很显然,就是要求每个蛋糕切出来的蛋糕总数大于等于总人数。
即: t o t a l = ( h [ i ] / e d g e ) ∗ ( w [ i ] / e d g e ) > = k total=(h[i]/edge)*(w[i]/edge)>=k total=(h[i]/edge)(w[i]/edge)>=k
上面total就是一个for循环的事。

编写代码

#include<iostream>
using namespace std;
const int N=1e5+10;
//巧克力个数和人数
int n,k;
//   长   宽
int h[N],w[N];

bool check(int num)
{
    //记录巧克力的个数
    int count=0;
    for(int i=0;i<n;i++)
    {
        //累加第i个巧克力分成成的小巧克力
        count+=(h[i]/num)*(w[i]/num);
    }
    if(count>=k)return true;
    return false;
}

int main()
{
    cin>>n>>k;
    for(int i=0;i<n;i++)cin>>h[i]>>w[i];
    
    int l=1,r=1e5;
    //进行二分
    while(l<r)
    {
        //向上取整
        int mid=l+(r-l+1>>1);
        if(check(mid)) l=mid;
        else r=mid-1;
    }
    //输出巧克力的边长
    cout<<r<<endl;
    return 0;
}

2.数组中数值和下标相等的元素

题目描述:
在这里插入图片描述
这道题就是一个很常规的二分模版题。

编写代码:

class Solution {
public:
    int getNumberSameAsIndex(vector<int>& nums) {
        int l=0,r=nums.size()-1;
        while(l<=r)
        {
            //找到中间数下标
            int mid=(l+r+1)/2;
            if(mid>nums[mid]) l=mid;
            else if(mid<nums[mid]) r=mid-1;
            else return nums[mid];
        }
        return -1;
    }
};

3.0到n-1中缺失的数字

题目描述:
在这里插入图片描述
这道题也是一个很常规的二分题。

class Solution {
public:
    int getMissingNumber(vector<int>& nums) {
        if(nums.size()==0)return 0;
        if(nums.size()==1)return 1;
        int l=0,r=nums.size()-1;
        while(l<r) 
        {
            int mid=(l+r+1)/2;
            if(mid==nums[mid])l=mid;
            else if(mid<nums[mid])r=mid-1;
        }
        if(nums[r]!=r)return r;
        else return r+1;
    }
};

4.数列分段 II

题目描述:
在这里插入图片描述
这道题的意思就和很简单,给定一个长度为N个数组,让我们将这个数组分为M段,因为有很多种分法,所以每个分法的每段中肯定能选出最大值,所以这道题的意思就是让我们求出所有分法中的最大值的最小值。

解题思路

这道题还是延续我们第一道题的想法,这道题求的是每个每种分法的最大值的最小值,所以我们对最大值进行二分,首先我们来确定二分的范围,由于是求分段的和,所以这个和肯定不可能比这数组中最大的还小,所以二分的下限肯定是数组中的数的最小值。二分的上限是数组的和(不可能你一个段的和比整个数组的和还大吧)
二分的区间已经确定了,应该确定二分的条件了,利用一点点贪心从第一个位置开始顺序的进行分段,用一个sum来维护这个段的和,用一个seg来维护段数。
在这里插入图片描述
如果当前段的和加上下一个即将入段的数小于等于需要二分的数的话,就将这个数入段,如果大于大于当前的数,那么就开辟新的段,这里的开辟新的段只需要将seg++,然后将sum置为下一个数即可,最后看分出的段是否小于给定的段数,如果小于的话说明成立,则返回true,如果大于的话说明不成立,直接返回false。(为什么只需要小于,因为如果小于的话,指定的段数是肯定能补足的)
在这里插入图片描述

如果成立的话说明还有比这个数更小的数,则下一次二分二分的区间就是l到当前数。
如果不成立的话说明这个数足够小了,没有满足的即二分的区间是当前数到r。

编写代码

#include<iostream>
using namespace std;
const int N=1e5+10;
int n,m,a[N];

bool check(int num)
{
    int seg=0,sum=0;
    for(int i=0;i<n;i++)
    {
        if(sum+a[i]<=num) sum+=a[i];
        else
        {
            sum=a[i];
            seg++;
        }
    }
    return seg<m;
}

int main()
{
    cin>>n>>m;
    int l=0,r=0;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
        l=max(l,a[i]);
        r+=a[i];
    }
    
    while(l<r)
    {
        int mid=(l+r)/2;
        if(check(mid))r=mid;
        else l=mid+1;
    }
    cout<<l<<endl;
    return 0;
}

总结

二分查找不仅是一种高效的算法,更是一种通用的解题思想。它通过每次将问题规模减半,显著提高了查找效率,尤其适用于有序数据或可以通过特定条件划分搜索空间的问题。在实际编程中,熟练掌握二分查找的应用场景和技巧,不仅能帮助解决许多算法题,还能拓宽你对算法优化的思考维度。因此,深入理解二分的原理,并善于在各种场景中运用它,是提升算法能力的重要一步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2216502.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何实现前端低代码?

昨天收到在后台收到一封朋友的私信。内容如下&#xff1a; 你好&#xff0c;我关注你很久了&#xff0c;看你经常在发低代码的内容&#xff0c;内容也很好&#xff0c;所以想跟您请教一下。 最近练手在写一个低代码项目&#xff0c;实现前后端可视化应用搭建 后端采用c#&#x…

过期大米被重新销往乡村学校?论EasyCVR平台如何构建校园食品卫生安全视频监管方案

近期&#xff0c;重庆市市场监管局发布的一则通报引起了社会广泛关注。通报指出&#xff0c;酉阳县某公司存在将过期大米重新包装并销往乡村学校的行为&#xff0c;这一事件再次将校园食品卫生安全问题推向了风口浪尖。 面对这样的食品安全隐患&#xff0c;如何加强监管、确保…

【linux问题】Linux命令行终端窗口的输出,显示不全问题

Linux命令行终端窗口的输出&#xff0c;显示不全问题 问题&#xff1a; 图中显示的是一个Linux命令行终端窗口&#xff0c; nmcli dev wifi 是一个命令——列出所有能用的Wi-Fi。 执行命令后&#xff0c;窗口输出了显示了所有能用的Wi-Fi网络列表。 但是在每一行末尾有一个“…

使用API有效率地管理Dynadot域名,删除域名服务器(Name Server)

前言 Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮箱&…

2-STM32入门

STM32入门 意法半导体公司推出STM32芯片。 只需动手。 第一步安装开发环境。 STM32CubeIDE 点灯大师 1.新建工程 File -> New -> STM32 Project 选择自己的开发版型号&#xff0c;输入项目名称&#xff0c;创建一个STM32工程。 点亮红色小灯的引脚为PB0(不了解的…

头戴式耳机性价比高的品牌有哪些?五款头戴式耳机200元左右推荐

耳机作为最被广大用户接受的数码产品&#xff0c;相信很多小伙伴都会拥有一个&#xff0c;甚至多个。但…在众多耳机样式中&#xff0c;如果论音质&#xff0c;同价位中头戴式应该是最好的&#xff0c;毕竟全包耳设计&#xff0c;能够让其有效隔绝外界噪音&#xff0c;实现更加…

svg全链路流程轨迹

直接上效果 <template><div class"right-page"><div class"container"><div class"line-wrap"><svgversion"1.1"xmlns"http://www.w3.org/2000/svg"xmlns:xlink"http://www.w3.org/1999/…

如何在极速浏览器中实现谷歌浏览器的扩展功能

在当今数字化时代&#xff0c;浏览器扩展功能极大地增强了我们的在线体验。尤其是谷歌浏览器&#xff0c;以其丰富的扩展生态而闻名。但是&#xff0c;如果你想在极速浏览器中使用这些谷歌浏览器的扩展功能&#xff0c;该怎么办呢&#xff1f;本文将为你详细解析如何实现这一目…

【Golang】Go语言http编程底层逻辑实现原理与实战

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

前端全栈混合之路Deno篇:Deno2.0与Bun对比,谁更胜一筹?它们分别适合怎样的项目,谁更适合前端转全栈?

在前端全栈开发中&#xff0c;工具的不断演变让开发者们始终在寻找更高效、更现代化的解决方案。继Node.js之后&#xff0c;Deno和Bun 成为了两个比较火热的运行时。Deno2.0的近期的发布让它在性能和兼容性方面大幅提升-尤其是兼容了npm包&#xff08;但我感觉应该不是全部兼容…

Linux源码阅读笔记-设备驱动程序

基础知识 Linux 内核输入子系统是对分散、多种不同类别的输入设备&#xff08;鼠标、键盘、触摸屏、手写板等&#xff09;进行统一的驱动程序。优势&#xff1a;统一物理形态各异相似输入设备处理功能&#xff1b;提供分发输入报告给用户应用程序的简单事件接口&#xff1b;抽…

DW-大模型生图安全疫苗注入作业记录

Task1.跑通baseline Task2.赛题评测方法 //------------------------------------------------------------------------- Task1-BaseLine 创建实例后与你运行代码&#xff0c;git clone model 太慢了 上modelspace 找到通义千问下载 模型下载慢问题 解决办法 modelscope do…

【数据分析】估算问题(费米估算问题)

1. 费米估算 费米估算问题是一种估算方法&#xff0c;它要求在没有足够信息的情况下&#xff0c;通过合理的假设和简化模型来计算一个复杂问题的大致答案。这种估算方法以意大利物理学家恩里科费米命名&#xff0c;他以能够在没有精确数据的情况下进行快速而准确的估算而闻名。…

ssm基于Web的老年公寓信息管理+jsp

系统包含&#xff1a;源码论文 所用技术&#xff1a;SpringBootVueSSMMybatisMysql 免费提供给大家参考或者学习&#xff0c;获取源码请私聊我 需要定制请私聊 目 录 目 录 III 第1章 绪论 1 1.1 课题背景 1 1.2 课题意义 1 1.3 研究内容 2 第2章 开发环境与技术 3 …

web3还未真正普及,网页已经漂亮的不像话了。

尽管 Web3 还未真正普及开来&#xff0c;但如今的网页已经呈现出令人惊叹的美丽景象。设计师们凭借着先进的技术和无限的创意&#xff0c;打造出一个个精美绝伦的网页界面。 色彩的搭配和谐而富有吸引力&#xff0c;布局合理且充满艺术感。动画效果生动活泼&#xff0c;为用户…

YOLOv8模型改进 第七讲 一种新颖的注意力机制 Outlook Attention

随着目标检测技术的不断发展&#xff0c;YOLOv8 作为最新一代的目标检测模型&#xff0c;已经在多个基准数据集上展现了其卓越的性能。然而&#xff0c;在复杂场景中&#xff0c;如何进一步提升模型的检测精度和鲁棒性依然是一个重要挑战。本文将探讨将 Outlook Attention 机制…

头戴式耳机300元预算选择有哪些?头戴式耳机300元左右五款推荐!

晚上下班或周末在家&#xff0c;想要沉浸式观影、游戏&#xff0c;肯定少不了一款头戴式耳机&#xff0c;它的两个大耳罩既不会像入耳式耳机那样对耳仓产生压迫不适感&#xff0c;也能全面包裹耳朵必要时尽可能的隔绝外界环境音&#xff0c;比那种把耳朵开放在外的骨传导耳机更…

FreeRtos到底是什么?

一&#xff0c;RTOS的全称是Real time operating system&#xff0c;中文就是实时操作系统 FreeRTOS是一个迷你的实时操作系统内核。作为一个轻量级的操作系统&#xff0c;功能包括&#xff1a;任务管理、时间管理、信号量、消息队列、内存管理、记录功能、软件定时器、协程等&…

lua脚本使用cjson转换json时,空数组[]变成了空对象{}

一、前言 项目lua使用工具&#xff1a;cjson 问题&#xff1a;reids中部分数据的json key存在为[]的值&#xff0c;使用cjson进行解析的时候将原本空数组[]解析成了空对象{} 目标&#xff1a;原本[] 转 [] 二、解决方案 在使用cjson类库时&#xff0c;先配置json转换要求 -…

信息与计算科学:“数学 + 计算机”,奏响未来科技新乐章

在当今科技飞速发展的时代&#xff0c;有一个专业如同一颗闪耀的新星&#xff0c;散发着独特的魅力&#xff0c;那就是信息与计算科学专业。 一、专业全貌&#xff1a;追根溯源&#xff0c;领略交叉之美 &#xff08;一&#xff09;专业的诞生与发展 1998 年&#xff0c;教育…