【算法】【二分法】二分法详解

先给y总打一个广告。(我这种废物收不到钱)
本科时候就在打蓝桥杯玩玩算法,当时听朋友的一个刷题且涵盖教程的网站,ACWING。
www.acwing.com
里面好处是大部分基础算法都有,Y总的视频! y总我的神!!!!。
非常适合萌新学学算法之类的。废物(比如说我)全都忘光了也能进去看看

前几天刷LeetCode100刚好有一个算法思路使用二分作为一个优化,发现自己对于二分理解不是很到位,所以就回去研究了一下,发现之前确实缺失太多。。。。
但还好看几个小时也能弄懂了。

但我刷别人教程,感觉写的还不是很明白??索性自己记录一下。不然就可以Copy别人的了,可恶,没被我找到。

基础

二分基础非常好理解,算是作为一个intro部分。后面基本遇不到这么简单的环境感觉。

场景:给你一个单调递增的序列,让你找到其中的一个数。当然递增递减无所谓。但我们额外一个假设是所有数字在这个数组里面唯一。
好,这个就是一个二分的标准模板。
首先先明确一下我们的目标:我们用二分的目标是优化时间复杂度
假设说我现在不知道二分,那我肯定没啥办法,直接暴力循环一个一个看,那么这样子的时间复杂度就是O(N)
但如果使用二分的话,就能够直接将这个时间复杂度直接降到O(log n)

先理解一下算法思想:
这个场景式给定了一个具体的区间,首先我们可以先看一下区间的中点,那么这时候就有三种情况:

  1. 区间中点就是你要的target,这时候皆大欢喜,直接return。
  2. 区间中点比target小,那这时候一想,我区间中点都比我的target小,那么我的target一定在我的右边吧。这时候就可以把左边砍掉。
  3. 区间中点比target大,跟上面同理,右边就不用看了。

所以看2,3这两种情况,他都能将原本的区间砍半,然后变为原本区间的一半,那么就等价于我们最早的假设,在一个区间找一个数,只不过这个区间比原来少了一半。那不就递归了,可以写代码了。
也正是这个砍半,所以能够将原本时间复杂度降到log n

大致代码框架


func binarySearch(arr []int, al int, ar int, tar int) int {l, r := al, ar					// search的区间for l < r {mid := (l + r) >> 1if arr[mid] == tar {		// 根据条件,修改区间l,rreturn mid} else if arr[mid] > tar {r = mid - 1} else {l = mid + 1}}return l
}

进阶

首先,先来参透一下二分的本质。

刚刚那个intro里面,目标其实是降低复杂度。但是为什么能够降低复杂度,他的核心是什么?实际上他的核心在于他能够直接将一半的区间都不需要考虑。那么为什么他能够让一半的区间都不需要考虑?
因为这里的MID实际上代表了他右边(左边)的一整个群体,只要这个MID不满足条件,那么他的另外一半一定不满足

所以二分本质不是单调,而在于二分类,只不过单调这个性质很容易就能够达到二分类的效果

基于这个逻辑,我就更希望让刚刚基础版本考虑三种情况降到只考虑两种情况。(实际上是我瞎说的,只不过现在算法里面大家都考虑两种情况)

怎么弄成只考虑两种情况?很简单,还是按照刚刚环境,第一个不是 == 那你把他随便归类到其中一个,把其中一个改为 <= 或者另外一个改为 >= 就完事了。

那我怎么找到这个target?还是一样找吧,因为他还是在你的目标区间里面吧。
但很有意思的是两种分法使得,二分法变成了两种现象。刚刚提及归类有两种方法吧,一种可以将他归为左边,一种将他归为右边。

所以就变成了查找某个区间的端点。而这个值要么是你的target,要么就是比你的target恰好大一点或者小一点
在这里插入图片描述
也就是寻找图中红色端点,或者图中绿色的端点。

而这里对应这个两个模板


func BL(arr [] int, sl int, sr int, tar int) int {l, r := sl, srfor l < r {mid := (l + r + 1) >> 1		// 必有加if arr[mid] <= tar {l = mid} else {r = mid - 1 	// 有减}}return l
}func BR(arr [] int, sl int, sr int, tar int) int {l, r := sl, srfor l < r {mid := (l + r) >> 1if arr[mid] >= tar {r = mid} else {l = mid + 1 	}}return l
}

上面代码的BL就对应查找图中红色端点,BR就对应查找图中蓝色端点。

解释一下代码更好背代码。

先解释红色:(这里场景还是用刚才那个,也就是数组单调递增等等)

首先,你找红色,那就是把你的target并到左边那边,而这里面的左边也就可以认为是所有比target小或者等这一类。

其次我们都假设true会怎么样,false会怎么样。

true的话就说明我的这个mid落在了红色这个区间,但是我是希望能够找到更为接近的右端点把?所以这时候我就需要更新l 为我的mid。因为这个mid依旧符合这个红色区间条件,所以我并不能把他排除。需要让他进行下一步考虑。
false的话就说明这个mid落在了绿色这个区间,那肯定是错的。所以这时候就要让r改为mid-1

然后仔细看 这里mid在算的时候,不是简单算中点,为什么?

  • 很简单,你套用区间只有两个数的情况,比如是1,2 而你的target是1.那这时候如果mid算中点,也就是 l + r >> 1,这时候结果就是0,还是这个1,结果是true, 所以就会调整 l=mid,那么这时候区间还是没有改变,就会进入到死循环,所以这里就有个+1

口诀有减必有加

同理,另外一个类似的推一下也就出来了,所以刚刚哪两个就是分别对应求不同区间的模板,自己看着用就行。

所以这时候就可以用二分法来解决很多问题。

acwing例题:789. 数的范围
标准的例题,做完应该就算会了

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

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

相关文章

LLMs 入门实战系列

【LLMs 入门实战系列】 第一层 LLMs to Natural Language Processing (NLP) 第一重 ChatGLM-6B 【ChatGLM-6B入门-一】清华大学开源中文版ChatGLM-6B模型学习与实战 介绍&#xff1a;ChatGLM-6B 环境配置 和 部署 【ChatGLM-6B入门-二】清华大学开源中文版ChatGLM-6B模型微调…

行为模式9.策略模式------促销活动设计方案

行为型模式 模板方法模式&#xff08;Template Method Pattern&#xff09;命令模式&#xff08;Command Pattern&#xff09;迭代器模式&#xff08;Iterator Pattern&#xff09;观察者模式&#xff08;Observer Pattern&#xff09;中介者模式&#xff08;Mediator Pattern…

Rust入门实战 编写Minecraft启动器#5启动游戏

首发于Enaium的个人博客 好了&#xff0c;我们已经完成了所有的准备工作&#xff0c;现在我们可以开始编写启动游戏的代码了。 首先我们需要添加几个依赖。 model { path "../model" } parse { path "../parse" } download { path "../downlo…

ensp防火墙综合实验作业+实验报告

实验目的要求及拓扑图&#xff1a; 我的拓扑&#xff1a; 更改防火墙和交换机&#xff1a; [USG6000V1-GigabitEthernet0/0/0]ip address 192.168.110.5 24 [USG6000V1-GigabitEthernet0/0/0]service-manage all permit [Huawei]vlan batch 10 20 [Huawei]int g0/0/2 [Huawei-…

python 端口的转发

实现端口的转发 tcpsocket.py 对基础的socket进行了封装 import socketclass baseSocket:def service(host:str,port:int,maxSuspend:int)->socket: service_socket socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 创建 socket 对象service_socket.setso…

GPT的架构与应用 - Transformer教程

在过去的几年里&#xff0c;人工智能技术取得了巨大的进展&#xff0c;其中最引人注目的成就是生成式预训练变换器&#xff08;GPT&#xff09;的出现。GPT是一种基于Transformer架构的模型&#xff0c;已在自然语言处理&#xff08;NLP&#xff09;领域掀起了革命性变化。今天…

springboot vue 实现验证码

要在Spring Boot和Vue.js中实现验证码功能&#xff0c;可以按照以下步骤进行操作&#xff1a; 在Spring Boot项目中添加验证码相关的依赖。可以使用Google的Kaptcha库来生成验证码图片。在pom.xml中添加以下依赖&#xff1a; <dependency><groupId>com.github.pe…

安全开发--多语言基础知识

注释&#xff1a;还是要特别说明一下&#xff0c;想成为专业开发者不要看本文&#xff0c;本文是自己从业安全以来的一些经验总结&#xff0c;所有知识点也只限于网络安全这点事儿&#xff0c;再多搞不明白了。 开发语言 笼统的按照是否编译成机器码分类开发语言&#xff0c;…

Perl 语言开发(十二):面向对象编程,深入理解与实践

目录 1. 概述 2. 面向对象编程基础 2.1 类与对象的基本概念 3. Perl中的面向对象编程 3.1 定义类和对象 3.1.1 创建类 3.1.2 创建对象 3.2.1 访问器和修改器 3.3 继承 3.3.1 创建基类 3.3.2 创建子类 3.3.3 使用继承 3.4 多态 3.4.1 方法重写 3.4.2 动态绑定 4…

git常用命令及git分支

git常用命令及git分支 git常用命令设置用户签名初始化本地库查看本地库状态将文件添加到暂存区提交到本地库查看历史记录版本穿梭 git分支什么是分支分支的好处分支的操作查看分支创建分支切换分支合并分支合并冲突 git常用命令 设置用户签名 //设置用户签名 git config --gl…

linux-conda环境安装教程

Linux Conda 环境安装教程 本文档详细介绍了在 Linux 系统上安装和使用 Conda 环境的步骤。 1. 安装 Conda 1.1 下载 Anaconda 安装包 首先&#xff0c;访问 Anaconda 官方网站 并下载适用于 Linux 系统的 Anaconda 安装包。 或者使用以下命令直接从终端下载&#xff1a; …

Datawhale 2024 年 AI 夏令营第二期——基于术语词典干预的机器翻译挑战赛

#AI夏令营 #Datawhale #夏令营 1.赛事简介 目前神经机器翻译技术已经取得了很大的突破&#xff0c;但在特定领域或行业中&#xff0c;由于机器翻译难以保证术语的一致性&#xff0c;导致翻译效果还不够理想。对于术语名词、人名地名等机器翻译不准确的结果&#xff0c;可以通…

emqx 负载均衡配置 HAProxy 健康检查 轮询 haship

HAProxy配置文件 配置文件&#xff1a; /etc/haproxy/haproxy.cfg 负载均衡参数&#xff1a; 轮询方式轮询注解roundrobin基于权重进行轮叫调度的算法&#xff0c;在服务器的性能分布比较均匀时&#xff0c;这是一种最公平合理&#xff0c;常用的算法。此算法使用较为频…

【银河麒麟高级服务器操作系统】数据中心系统异常卡死分析处理建议

了解银河麒麟操作系统更多全新产品&#xff0c;请点击访问&#xff1a;https://product.kylinos.cn 1.服务器环境以及配置 【机型】浪潮NF5280M5 处理器&#xff1a; Intel 内存&#xff1a; 1T 【内核版本】 4.19.90-24.4.v2101.ky10.x86_64 【OS镜像版本】 银河麒麟…

PDF 中图表的解析探究

PDF 中图表的解析探究 0. 引言1. 开源方案探究 0. 引言 一直以来&#xff0c;对文档中的图片和表格处理都非常有挑战性。这篇文章记录一下最近工作上在这块的探究。图表分为图片和表格&#xff0c;这篇文章主要记录了对表格的探究。还有&#xff0c;我个人主要做日本项目&…

MFC Ribbon菜单 - 中英文实时切换方法

简介 最近在搞一个老外的项目&#xff0c;本来谈的好好的&#xff0c;纯英文界面。项目接近尾声了&#xff0c;又提出了中英文实时切换的新需求&#xff0c;没办法就只能想办法&#xff0c;毕竟客户最大嘛。 实现方法 还好本来的ribbon英文菜单不复杂&#xff0c;就用纯C编码…

Android上如何使用perfetto分析systrace

Android上如何使用perfetto分析systrace Perfetto 是一个用于性能分析的工具&#xff0c;提供了对 Android 系统内部工作情况的详细视图。它可以用来替代传统的 systrace 工具&#xff0c;提供更加全面的性能分析功能。以下是如何使用 Perfetto 分析 Systrace 数据的详细指南&…

粉丝问我:大龄干运维还有出路吗?

这兄弟&#xff1a; 18年参加培训班&#xff0c;培训的java&#xff0c;结果学的不好。又去机构学了linux云计算&#xff0c;去做了运维&#xff0c;19年去一家网络公司做了idc&#xff0c;可以说这两年自己不努力&#xff0c;什么都没学到&#xff0c;基本等于零。 我现在就…

Python轻松添加行编号到Word文档及删除行编号

Word文档中的行号&#xff08;行编号&#xff09;功能是对于精细化的文档编辑以及解析非常有用的功能。添加行号能够极大地提升文档的可读性和定位效率&#xff0c;尤其是在需要引用特定行内容时&#xff0c;为读者提供了清晰的指引&#xff0c;避免了不必要的混淆和误解。然而…

Java BigInteger 类

目录 BigInteger 1. 如何获取一个BigInteger类型的对象&#xff1f; &#xff08;1&#xff09;构造方法 &#xff08;2&#xff09;静态方法 2. 常用方法 BigInteger 可以用来表示很大很大的数&#xff0c;有多大都可以。通过创建对象调用相应的方法。详见&#xff1a;…