二分答案算法

基本概念

将最值问题转换为判定

与二分查找的区别

二分查找:在一个已知的有序数据集上进行二分地查找

二分答案:答案有一个区间,在这个区间中二分,直到找到最优答案

如何判断一个题是不是用二分答案做的

1、答案在一个区间内(一般情况下,区间会很大,暴力超时)

2、直接搜索不好搜,但是容易判断一个答案可行不可行

3、该区间对题目具有单调性,即:在区间中的值越大或越小,题目中的某个量对应增加或减少。

此外,可能还会有一个典型的特征:求...最大值的最小 、 求...最小值的最大。

1、求...最大值的最小,我们二分答案(即二分最大值)的时候,判断条件满足后,尽量让答案往前来(即:让r=mid)

2、同样,求...最小值的最大时,我们二分答案(即二分最小值)的时候,判断条件满足后,尽量让答案往后走(即:让l=mid)

例题

875. 爱吃香蕉的珂珂

题目

珂珂喜欢吃香蕉。这里有 n 堆香蕉,第 i 堆中有 piles[i] 根香蕉。警卫已经离开了,将在 h 小时后回来。

珂珂可以决定她吃香蕉的速度 k (单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉 k 根。如果这堆香蕉少于 k 根,她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉。  

珂珂喜欢慢慢吃,但仍然想在警卫回来前吃掉所有的香蕉。

返回她可以在 h 小时内吃掉所有香蕉的最小速度 kk 为整数)。

示例 1:

输入:piles = [3,6,7,11], h = 8
输出:4

示例 2:

输入:piles = [30,11,23,4,20], h = 5
输出:30

示例 3:

输入:piles = [30,11,23,4,20], h = 6
输出:23

提示:

  • 1 <= piles.length <= 104
  • piles.length <= h <= 109
  • 1 <= piles[i] <= 109

思路:

比如:

  • [6,4 ,5,2,4,3],离开20h
  • 假如说速度是5根/1h
  • 1)6->1
  • 2)1->0
  • 然后休息
  • 3)4->0
  • 休息
  • 有富余的时间就休息了,没富余时间继续吃下一堆
  • 推下来5达标满足
  • 然后推下来4也达标
  • 要求速度尽量小还要达标
  • 1不达标....2达标(所以答案是2)
  • 速度最小就是1,而速度的最大值就是数组最大值因为就算定的越大(比数组最大值还大)都是1h内吃完,时间并没有任何变化
  • 所以可以得到题目的答案(最小还达标)是在这个区间的
  • 这个区间是单调性的:
  • 速度变大花费的时间是越小的,比如说速度为6那么花费的时间是a小时,速度为7花费的时间是b小时,那么a >= b 的,也就是在最大中找最小
  • 这道题就是速度越大越有可能达标,速度越小越不可能达标(比如说速度4是达标的,那么意味着速度5,6,7,8都是达标的),满足答案是单调的,所以能够通过对答案进行二分得到最终答案
  • 对答案二分过程:
  • 比如:1,2,3,4,5,6,7,8
  • 第一次二分,检查4是否达标
  • 如果4达标,及一个答案ans = 4,然后再1~3这个范围取一个更小的检查是否答案,因为题目要求的是最小还达标,如果2不达标,那么不计入答案,ans还是4,去3~3范围二分检查。
  • 如果4不达标,那么意味着1~3都不达标,ans不记录答案去右侧二分,然后在5~8区间二分,6还不达标那么再在右侧二分,也就是7,8,发现7达标,记录答案ans = 7,那么在7的左侧二分,发现7的左侧已经没了,那么答案就是7了
  • 那么我们需要一个check函数检查是否达标:
  • 也就是检查用给的中间值的速度吃这堆香蕉花的时间。

具体代码讲解:

bool check(int* piles, int pilesSize, int h, int mid) {long int sum = 0;for (int i = 0; i < pilesSize; i++) {if (piles[i] % mid != 0) {sum += (piles[i] / mid) + 1;}else{sum+=piles[i]/mid;}}return sum <= h;
}
int minEatingSpeed(int* piles, int pilesSize, int h) {// 最小且达标的速度,范围[l,r]int l = 1;int r = 0;for (int i = 0; i < pilesSize; i++) {if (piles[i] >= r)r = piles[i];}//[l,r]不停的二分int ans = 0;while (l <= r) { // 直到二分范围消失int mid = (r + l) / 2;if (check(piles, pilesSize, h, mid)) {// 达标,记录答案// 左侧二分ans = mid;r = mid - 1;} else {// 不达标,不记答案// 右侧二分l = mid + 1;}}return ans;
}

410. 分割数组的最大值

题目

给定一个非负整数数组 nums 和一个整数 k ,你需要将这个数组分成 k 个非空的连续子数组。

设计一个算法使得这 k 个子数组各自和的最大值最小。

示例 1:

输入:nums = [7,2,5,10,8], k = 2
输出:18
解释:
一共有四种方法将 nums 分割为 2 个子数组。 
其中最好的方式是将其分为 [7,2,5] 和 [10,8] 。
因为此时这两个子数组各自的和的最大值为18,在所有情况中最小。

示例 2:

输入:nums = [1,2,3,4,5], k = 2
输出:9

示例 3:

输入:nums = [1,4,4], k = 3
输出:4

提示:

  • 1 <= nums.length <= 1000
  • 0 <= nums[i] <= 106
  • 1 <= k <= min(50, nums.length)

思路:

估计最终答案可能的范围

  • 每部分累加和求出来的最大值尽量小(答案)
  • 整个数组的和为A
  • [0,A]
  • 范围定得比较粗糙,可以定得特别粗糙,毕竟二分时间复杂度很低

分析问题的答案和给定条件之间的单调性

  • 比如范围0~1000,对0~1000进行二分->500,相当于k份都要满足累加和<=500,
  • 假如二分得600,也就是每一部分的累加和都<=600,那么条件放宽了,越有可能达标,
  • 也就是答案越大越有可能,越小越不可能

建议一个check函数,当答案固定的情况下,判断给定的条件是否达标

  • 根据题目建立check函数,在这道题当中check:
  • 我们必须让数组每一份累加和满足<=mid,得到数组当中划分几部分可以满足这个要求,然后判断部分综合是否超过题目要求,超过了就是不达标没超过就是达标
  • 比如[4,5,1,6,8,5,9]假如这时中间值是11,那么4+5+1小于11,如果加上6那么就多了,就开始装下一个part,起点从6开始。
  • 但如果数组中有一个元素直接大于了给的中间值比如[3,3,77]假如给的中间值是15,77直接大于了15,那么我们要直接返回没有方案(即false)

在最终答案可能的范围上不断二分搜索,每次使用check函数判断,直到二分结束,找到最合适的答案

bool check(int* nums, int numsSize, int k, int mid) {// 必须让数组每一份的累加和满足<=mid,请问划分成几个部分才够// 一直加加到要超了,就停,代表一个子达成,// 但如果单点的值就超过,直接用整数最大值表示没有方案int parts = 1;int sum = 0;for (int i = 0; i < numsSize; i++) {if (nums[i] > mid) {return false;}if (sum + nums[i] > mid) {parts++;sum = nums[i];} else {sum += nums[i];}}return parts <= k;
}
int splitArray(int* nums, int numsSize, int k) {long int sum = 0;for (int i = 0; i < numsSize; i++) {sum += nums[i];}long int ans = 0;long int l = 0;long int r = sum;//[0,ans]二分while (l <= r) {// 必须让数组每一份的累加和满足<=mid,请问划分成几个部分才够int mid = (l + r) / 2;if (check(nums, numsSize, k, mid)) {// 如果你需要的部分数量<=给你的部分的数量说明达标ans = mid;r = mid - 1;} else {l = mid + 1;}}return ans;
}

总结

  1. 估计最终答案可能的范围
  2. 分析问题的答案和给定条件之间的单调性
  3. 建议一个check函数,当答案固定的情况下,判断给定的条件是否达标
  4. 在最终答案可能的范围上不断二分搜索,每次使用check函数判断,直到二分结束,找到最合适的答案
  5. 核心:分析单调性,建立check函数

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

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

相关文章

【GIS面试】GIS算法介绍

作者&#xff1a;后端小肥肠 1. 前言 在地理信息系统&#xff08;GIS&#xff09;的领域中&#xff0c;算法扮演着极其重要的角色&#xff0c;它们使得复杂的空间数据分析成为可能。无论是在环境科学、城市规划&#xff0c;还是在灾害管理等众多领域&#xff0c;高效和精确的算…

Zabbix监控Oracle归档日志空间

1、oracle查看归档日志空间的sql语句 select sum(PERCENT_SPACE_USED) from v$recovery_area_usage; 2、交互式查看oracle归档日志空间的命令&#xff0c;可以手动执行一下&#xff0c;注意要用oracle用户 sqlplus -S "/ as sysdba" << EOF select sum(PER…

解决“ImportError: DLL load failed while importing _rust: 找不到指定的程序的问题

运行 scrapy startproject wikiSpider 报错&#xff1a;ImportError: DLL load failed while importing _rust: 找不到指定的程序。 经过尝试 可以更换Python解释器版本来解决 1、点击crtlalts打开设置 点击项目>解释器 选择3.11解释器 &#xff08;我原来报错用的3.9的解…

企业车辆违章查询工具,批量查询企业名下车辆违章情况,专为网约车/出租车管理公司而生

功能介绍 功能分为&#xff1a;违章管理、车辆管理、任务管理 违章管理如图&#xff1a; 搜索条件为车牌号 筛选条件为&#xff1a;时间区间、企业选择、是否处理违章、是否缴纳罚款、所属车管员 车牌管理如图&#xff1a; 可以新增车牌 查询条件为&#xff1a;车牌信息、车…

【无人机路径规划】基于改进差分算法实现三维多无人机协同航迹规划附matlab代码

于改进差分算法实现三维多无人机协同航迹规划的课程设计大纲的示例: 研究背景 研究背景: 随着无人机技术的快速发展,无人机在各个领域中的应用越来越广泛,如监测、搜索救援、物流等。在一些任务中,需要多个无人机进行协同工作,例如进行搜索与救援任务时,多个无人机可以…

为什么Redis使用单线程 性能会优于多线程?

前言 在计算机领域&#xff0c;性能一直都是一个关键的话题。无论是应用开发还是系统优化&#xff0c;我们都需要关注如何在有限的资源下&#xff0c;实现最大程度的性能提升。Redis&#xff0c;作为一款高性能的开源内存数据库&#xff0c;因其出色的单线程性能而备受瞩目。那…

项目之旅(第三周)

文章目录 项目学习总结一、form表单的提交1&#xff09;、提交跳转型2)、ajax异步提交form表单&#xff0c;前端控制下一步走向型 二、.gitignore文件用法及如何配置三、点击除盒子之外的地方盒子隐藏四、thymeleaf复用div 项目总结生活总结 项目学习总结 一、form表单的提交 …

微信小程序手机授权报错:pad block corrupted

微信小程序手机号授权登录&#xff0c;传参至后台解密&#xff0c;大概率都会成功&#xff0c;但是&#xff0c;偶尔会遇到解密失败&#xff0c;报错信息为&#xff1a; javax.crypto.BadPaddingException: pad block corrupted&#xff1b;在此记录一下解决方案。 更改前获取…

【备战算法岗】—— 控制模块复习(持续更新!!!)

1 控制理论基础 1.1 控制模块概述 输入&#xff1a;轨迹线Reference、地图信息、定位信息、车辆反馈信息 输出&#xff1a;刹车、油门、转向 CANBUS&#xff1a;车辆底盘交互协议 参考博客&#xff1a;Apollo CANBUS模块解析 apollo&#xff1a;canbus模块&#xff08;1&…

如何完成三只青蛙任务?

如何完成三只青蛙任务&#xff1f; 本文介绍了如何有效完成 三只青蛙任务&#xff0c;包括匹配资源、保护青蛙和拒绝干扰事项。 同时&#xff0c;对于习惯缺乏动力的问题&#xff0c;建议考虑是否有必要去做这个习惯&#xff0c;或者寻找其他激励方法。 大家在践行过程中可能没…

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之二 简单人脸检测添加戴眼镜效果

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之二 简单人脸检测添加戴眼镜效果 目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之二 简单人脸检测添加戴眼镜效果 一、简单介绍 二、简单人脸检测添加戴眼镜效…

《机器学习by周志华》学习笔记-线性模型-02

1、对数几率回归 1.1、背景 上一节我们考虑了线性模型的回归学习,但是想要做分类任务就需要用到上文中的广义线性模型。 当联系函数连续且充分光滑,考虑单调可微函数,令: 1.2、概念 找一个单调可谓函数,将分类任务的真实标记与线性回归模型的预测值联系起来,也叫做「…

Kafka集群搭建可视化指南

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 Kafka集群搭建可视化指南 前言准备工作硬件要求环境准备 kafka集群的部署与配置3.1 单节点部署与多节点集群搭建单节点部署&#xff1a;多节点集群搭建&#xff1a; 3.2 Broker配置与优化3.3 Topic的创…

政安晨:【Keras机器学习示例演绎】(七)—— 利用 NeRF 进行 3D 体积渲染

目录 简介 设置 下载并加载数据 NeRF 模型 训练 可视化训练步骤 推理 渲染三维场景 可视化视频 结论 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: TensorFlow与Keras机器学习实战 希望政安晨的博客能够对您有所裨益&#xff0…

在 Linux 操作系统中使用locate 命令快速定位文件和目录

在 Linux 操作系统中&#xff0c;locate 命令是一个非常实用的工具&#xff0c;用于快速定位文件和目录。它通过搜索系统的数据库来查找文件和目录的位置&#xff0c;而不是像 find 命令那样实时搜索文件系统。虽然在某些 Linux 发行版中 locate 命令并不默认安装&#xff0c;但…

open Gauss 数据库-05 openGauss数据库备份恢复指导手册

发文章是为了证明自己真的掌握了一个知识&#xff0c;同时给他人带来帮助&#xff0c;如有问题&#xff0c;欢迎指正&#xff0c;祝大家万事胜意&#xff01; 目录 前言 openGauss数据库备份恢复 1 实验介绍 1.1 关于本实验 1.2 实验目的 2 实验前提 3 物理备份和恢复…

「GO基础」在Windows上配置VS Code GO语言开发环境

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

Linux操作系统·Linux简介

1.世界上第一个完善的网络操作系统 Unix是1969年由美国电话电报公司(AT&T)贝尔实验室的两个工程师所创造的操作系统&#xff0c;它允许计算机同时处理多用户和程序。目前大型政府单位、大型企业、航空公司、金融机构多在使用&#xff0c;价钱昂贵&#xff0c;但性能和稳定性…

IoTDB数据库整合MyBatis实现SpringBoot项目CRUD

遇到的问题&#xff1a; 1.启动项目提示&#xff1a;testWhileIdle is true, validationQuery not set。 2023-04-26 14:05:39.282 ERROR 13864 --- [ main] com.alibaba.druid.pool.DruidDataSource : testWhileIdle is true, validationQuery not set原因&#…

车载诊断的基本框架和概念

车载诊断的基本框架和概念 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不…