【LeetCode 算法专题突破】二分查找(⭐)

文章目录

  • 前言
  • 1. 二分经典模板题目
    • 题目描述
    • 代码:
  • 2. 在排序数组中查找元素的第一个和最后一个位置
    • 题目描述
    • 代码
  • 3. 有效的完全平方数
    • 题目描述
    • 代码
  • 4. 寻找峰值
    • 题目描述
    • 代码
  • 5. 寻找旋转排序数组中的最小值
    • 题目描述
    • 代码
  • 6. 点名
    • 题目描述
    • 代码
  • 总结

前言

我刷过不少算法题目,也得过算法竞赛的奖状,但是并没有成体系的总结,或者说学习算法的类型,所以我决定把常见的算法进行一次归类,然后总结每个经典类型的算法的知识重点,加强算法能力,完善算法体系,也希望能对你有所帮助~

1. 二分经典模板题目

力扣链接:https://leetcode.cn/problems/binary-search/

题目描述

题目描述
这道题目是一道非常经典的二分查找的模板题,可以说,所有二分算法入门都离不开这道题目,题目的要求很简单,就是从一段有序的数组中查找 target 值。

代码:

func search(nums []int, target int) int {left, right := 0, len(nums)-1for left <= right {mid := left+(right-left)/2if nums[mid] < target {left = mid+1} else if nums[mid] > target {right = mid-1} else {return mid }}return -1
}

我的习惯是每做完一道题目,要能从题目中学习到一些什么,也许是熟练度,也许是对这个算法的理解加深了,那做完这道题目我学到了什么?

我加深了对二分查找排除区间的理解:

当 mid 位置的值小于 target(nums[mid] < target ),证明左半边的区间,包括 mid 位置,不可能存在 target 值,所以左区间 left = mid+1;

当 mid 位置的值大于 target(nums[mid] > target),证明右半边的区间,包括 mid 位置,不可能存在 target 值,所以右区间 right = mid-1;

当 mid 位置等于 target,那当然就证明找到了,可以 return 了。

我个人认为这道题目的核心思想,或者说二分的一个思想,就体现在这里

2. 在排序数组中查找元素的第一个和最后一个位置

现在你已经学会二分了,来一道变式题试试吧~

题目链接:https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/

题目描述


这道题的难点其实就是怎么求到 target 值的起点和终点,那我们只需要用两次二分查找,分别查找他的起点和终点就行啦

代码

func searchRange(nums []int, target int) []int {left, right, begin, end := 0, len(nums)-1, -1, -1// 求左区间for left <= right {mid := left+(right-left)/2if nums[mid] > target {right = mid-1} else if nums[mid] < target {left = mid+1} else {begin = midright--}}// 恢复 left 和 rightleft, right = 0, len(nums)-1// 求右区间for left <= right {mid := left+(right-left)/2if nums[mid] > target {right = mid-1} else if nums[mid] < target {left = mid+1} else {end = midleft++}}return []int{begin, end}
}

这道题目的二分查找使用的方法和模板题是一模一样的,但是为了找到左右区间,我们在遇到 nums[mid] == target 情况,稍微进行了一些调整:

在找左区间的时候,我们记录下 begin 之后,让 right–,这样 mid 的位置也会不断向左,直到 nums[mid] != target,这样 begin 的值就是左区间

在找右区间的时候,我们记录下 end 之后,让 left++,这样 mid 的位置也会不断向右,直到 nums[mid] != target,这样 end 的值就是右区间

3. 有效的完全平方数

现在你已经学会在有序数组中使用二分查找了,那,如果题目没有给你有序数组,也没有提示你时间复杂度要求呢?作为一个算法菜鸟,我的办法就是:多刷题,见多识广(说人话:你刷过类似的题目不就会做了)

题目链接:https://leetcode.cn/problems/valid-perfect-square/description/

题目描述


抛开题目不谈,如果要你来求完全平方数,你会怎么做?那肯定是用原数折半之后乘一下看看对不对的上,对不上就继续折半,为什么这样做?因为这样效率很高~ 既然如此,那我们为什么不用二分做来试试

代码

func isPerfectSquare(num int) bool {left, right := 0, numfor left <= right {mid := left+(right-left)/2sqrt := mid*midif sqrt < num {left = mid+1} else if sqrt > num {right = mid-1} else {return true}}return false
}

咱也没有细想代码的细节,就是简单的把二分算法套进了这个场景,现在来看,以后如果遇到类似的问题,也可以用二分~

4. 寻找峰值

那接下来咱们就多刷一点题目,看看哪里还能用二分查找算法,增加我们的二分熟练度和能力~

题目链接:https://leetcode.cn/problems/find-peak-element/

题目描述


这道题我们连 target 值都没有,他甚至也不是一个有序的序列,我们能用二分算法来做吗?来看看代码

代码

func findPeakElement(nums []int) int {left, right := 0, len(nums)-1for left < right {mid := left+(right-left)/2if nums[mid] < nums[mid+1] {left = mid+1} else if nums[mid] > nums[mid+1] {right = mid}}return right
}

乍一看,我们好像无从下手,那就慢慢分析,看看该怎么解决。

题目要求我们要查找数组中任意一个峰值,那我们可以怎么找到峰值呢?我们可以分析到,其实这个数组无非就分为连个区间,一个是递增区间,一个是递减区间,而峰值就是两个区间交替的标志

假设我们随机找一个点,如果他比右边位置的值小,那就证明他在一个递增的区间;如果他比右边的位置的值大,那就证明他在一个递减的区间

通过这个性质,我们使用二分算法,当 nums[mid] < nums[mid+1] 时,在一个递增的区间,山顶必定在 mid+1 以及之后的位置;当 nums[mid] > nums[mid+1] 时,在一个递减的区间,山顶则可能在 mid 或者是之前的位置(这里要注意了,山顶有可能就是 mid 位置)

所以 right = mid,而不需要 -1 的操作。也因为这里不需要 -1,当 left == right 的时候,如果我们已经找到山顶了,那该怎么跳出循环?

这里我们可以选择特判一下,也可以把循环条件改成 left < right。有些时候,模板也不是一定要定死的,我们是可以根据实际情况进行调整的。这也我们做完这道题目学到的东西,又或者说积累到的经验。

5. 寻找旋转排序数组中的最小值

咱们继续来做一些不同场景下的二分的应用~

题目链接:https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array/

题目描述


这道题目的解题思路其实和上一道题类似,我们要根据题目给的条件,找到一个能够比较的参照物,或者说一个参照系。来看代码

代码

func findMin(nums []int) int {n := len(nums)-1left, right := 0, nfor left < right {mid := left+(right-left)/2if nums[mid] > nums[n] {left = mid+1} else if nums[mid] < nums[n] {right = mid}}return nums[left]
}

我们还是从题目条件出发,题目给出的是一个旋转过的升序数组,你发现,这又不是一个有序的数组,这该咋用二分来解呢?

分析一下,有序数组旋转之后,他会分成两个递增的区间,一个区间大,一个区间小,我们可以拿区间的最大值作为参照物

举个例子,这个数组最右边的值,他只有两种可能,1. 是小区间的最大值,2. 大区间的最大值(这种情况下,这个数组就是没有旋转过的情况,那我们可以先忽略特殊情况(这算是我的一点做题的技巧,因为特殊情况可以到时候想着怎么特判))

题目要求我们找到最小元素,也就是我们只需要找到小区间,再在小区间找到区间内最小元素即可,那就:

当 nums[mid] > nums[n] 时,mid 位置大于小区间的最大值,证明 mid 位置在大区间,所以让 left = mid+1;
当 nums[mid] < nums[n] 时,mid 位置小于小区间的最大值,证明 mid 位置在小区间,所以让 right = mid;因为我们要找的值就在小区间,所以不能 -1

然后我们在模拟一下特殊情况,当 nums[mid] < nums[n] 时,n 位置是大区间的最大值,让 right = mid 会导致最后的出现 left = right 的情况,那我们就把循环的条件调整为:left < right

又是一道变式的二分题目,其实我们只要分析出,以什么作为参照系来排除区间的位置,那之后的工作就很容易了~

6. 点名

那咱们就趁热打铁,再来最后一道,增强一下信心,以后二分题目就不用愁啦~

题目链接:https://leetcode.cn/problems/que-shi-de-shu-zi-lcof/

题目描述


这道题我其实一开始也想不出来,选这道题的目的其实也是想说明,算法积累的重要性,见多识广,才能思路开阔,临危不乱。来看代码:

代码

func takeAttendance(records []int) int {left, right := 0, len(records)-1for left < right {mid := left+(right-left)/2if records[mid] == mid {left = mid+1} else {right = mid}}if records[right] == right {return right+1}return right
}

分析题目我们看到,数组是从 0 开始一个升序数组,所以我们可以发现,数组中的数字是和下标是一一对应的,但是缺失了数字之后,数组的数就会比下标大,这样,我们又能将这个数组分为两个区间

我们画个图来看,会更加的清晰:

正常的区间是一一对应的,而失去数字的区间都是对不上的,如果对的上,也就是 records[mid] == mid,就让 left = mid+1;如果对不上,就让 right = mid,因为答案可能就在这个区间

现在就只剩下一个特殊情况了,如果消失的是最后一个数呢?那我们就最后特判一下就行

总结

相信你刷完这六道题目之后,二分已经不在话下了~

再接再厉,去迎接新的挑战吧~

如果哪天对二分又不熟悉了,也可以回来再刷一刷,练练手感~

最后,祝你今后刷题愉快~

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

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

相关文章

LeetCode【11】 盛水最多的容器

题目&#xff1a; 分析&#xff1a; 1、双指针&#xff0c;储水为&#xff08;R-L &#xff09;* 二者较小高度&#xff0c;如题目&#xff0c;(9-2)* 7 49 2、双指针向中间靠&#xff0c;每次移动较矮的指针。 代码&#xff1a; public int maxArea(int[] height) {int l…

适用于音视频的弱网测试整理

一、什么是弱网环境 对于弱网的定义&#xff0c;不同的应用对弱网的定义是有一定的差别的&#xff0c;不仅要考虑各类型网络最低速率&#xff0c;还要结合业务场景和应用类型去划分。按照移动的特性来说&#xff0c;一般应用低于2G速率的都属于弱网&#xff0c;也可以将3G划分…

【JAVA】最容易忽视的数据类型——枚举

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️初识JAVA】 前言 Java枚举是一个特殊的类一般表示一组常量,比如一年的 4个季节,一年的 12 个月份,一个星期的7天,方向有东南西北等。今天就让我们来学习一下在JAVA中这个特殊的类。 枚举 枚举是一…

10.12作业

以下是一个简单的比喻&#xff0c;将多态概念与生活中的实际情况相联系&#xff1a; 比喻&#xff1a;动物园的讲解员和动物表演 想象一下你去了一家动物园&#xff0c;看到了许多不同种类的动物&#xff0c;如狮子、大象、猴子等。现在&#xff0c;动物园里有一位讲解员&…

吃瓜神奇!企查查、天眼查、天眼销,到底哪家强?

最近&#xff0c;我发现很多人在讨论查企业信息的工具&#xff0c;什么企查查、天眼查、天眼销等&#xff0c;到底哪家强呢&#xff1f; 首先&#xff0c;我们来简单了解一下这些工具。企查查是一款可以帮助用户查询企业信息的工具&#xff0c;通过输入关键词&#xff0c;可以搜…

【VUE】element Table指定字段单元格样式及数据格式化

将列表中的指定字段的数据&#xff0c;根据字典值回显&#xff0c;并修改指定状态的显示样式 <el-tableref"table"height"500px":data"dataList"><template v-for"(item, index) in columns"><el-table-column:key&quo…

嵌入式面试常见问题(一)

目录 1.什么情况下会出现段错误&#xff1f; 2.swap() 函数为什么不能交换两个变量的值 3.一个函数有六个参数 分别放在哪个区&#xff1f; 4.定义一个变量&#xff0c;赋初值和不赋初值分别保存在哪个区&#xff1f; 5.linux查看端口状态的命令 6.结构体中->和.的区…

Tomcat自启动另一种方法

Tomcat自启动另一种方法 问题&#xff1a; 不知道怎么回事&#xff0c;好几台电脑都可以开机自启动tomcat&#xff0c;正常运行项目。一样的配置一样的操作流程&#xff0c;偏偏要运行的机器开机自启动后&#xff0c;项目不能运行&#xff0c;手动重启tomcat又可以用了。网上…

FHRP首跳冗余的解析

首跳冗余的解析 个人简介 HSRP hot standby router protocol 热备份路由协议 思科设备上 HSRP VRRP 华为设备上 VRRP HSRP v1 version 1 HSRP v2 version 2 虚拟一个HSRP虚拟IP地址 192.168.1.1 开启HSRP的抢占功能 通过其他参数 人为调整谁是主 谁是从 &a…

【低代码表单设计器】:创造高效率的流程化办公!

当前&#xff0c;有不少用户朋友对低代码表单设计器挺感兴趣。其实&#xff0c;如果想要实现提质增效的办公效率&#xff0c;创造一个流程化办公&#xff0c;那么确实可以了解低代码技术平台。流辰信息作为服务商&#xff0c;拥有较强的自主研发能力&#xff0c;根据市场的变化…

Mybatis入门

Mybatis mybatis是一款优秀的持久层框架&#xff0c;用于简化JDBC的开发。&#xff08;控制层 controller&#xff09;&#xff08;业务层service&#xff09;&#xff08;持久层dao&#xff09;&#xff08;数据库&#xff09; 快速创建springboot-mybatis工程 jdk选11 &am…

ubuntu下使用gcc编译c程序: “error: stray ‘\357’ in program“

现象&#xff1a; ubuntu下使用gcc编译c程序: “error: stray ‘\357’ in program“ 尝试查找原因&#xff1a;打开从windos直接粘贴c程序到ubuntu的c代码&#xff0c;发现多了 <200b>&#xff1a; 方案&#xff1a;尝试在vim编辑器删除&#xff0c;多出来的字符后编译…

ARM 按键控制 LED灯,蜂鸣器,风扇

main.c: #include "uart.h" #include "key_it.h" int main() {all_led_init();uart4_init();//串口初始化//中断初始化key_it_config();key3_it_config();buzzer_init();fan_init();while(1){//保证主程序不结束}return 0; }src/key_it.c: #include"…

小程序中使用echarts的相关配置以及折线图案例(简单易懂)

第一步&#xff1a;引入echarts文件--此文件需要下载&#xff1a; 下载地址&#xff1a;点击此处进行下载echarts文件 点击Download ZIP下载压缩包&#xff0c;注意&#xff1a;e-canvas是我从完整的文件中剥离出来的有用的&#xff0c;不会影响项目。 第二步&#xff1a;把整…

ctfshow萌新计划web9-14(正则匹配绕过)

目录 web9 web10 web11 web12 web13 web14 web9 审一下代码&#xff0c;需要匹配到system|exec|highlight才会执行eval函数 先看一下当前目录下有什么 payload&#xff1a;?csystem(ls); index.php是首页&#xff0c;我们看看config.php payload&#xff1a;?csystem…

nodejs+vue+elementui医院挂号预约管理系统4n9w0

前端技术&#xff1a;nodejsvueelementui 前端&#xff1a;HTML5,CSS3、JavaScript、VUE 1、 node_modules文件夹(有npn install Express 框架于Node运行环境的Web框架, 开发语言 node.js 框架&#xff1a;Express 前端:Vue.js 数据库&#xff1a;mysql 数据库工具&#xff…

邮政编码,格式校验:@ZipCode(自定义注解)

目标 自定义一个用于校验邮政编码格式的注解ZipCode&#xff0c;能够和现有的 Validation 兼容&#xff0c;使用方式和其他校验注解保持一致&#xff08;使用 Valid 注解接口参数&#xff09;。 校验逻辑 有效格式 不能包含空格&#xff1b;应为6位数字&#xff1b; 不校验…

AI「鸟口普查」,康奈尔大学利用深度学习分析北美林莺分布

据世界自然基金会统计&#xff0c;1970-2016 年&#xff0c;全球代表物种种群数量减少了 68%&#xff0c;生物多样性不断下降。 保护生物多样性&#xff0c;需要对当地生态情况进行准确分析&#xff0c;制定合理的生态保护政策。然而&#xff0c;生态数据太过庞杂&#xff0c;统…

小程序中如何设置所服务地区的时区

在全球化的背景下&#xff0c;小程序除了在中国使用外&#xff0c;还为海外的华人地区提供服务。例如我们采云小程序为泰国、阿根廷、缅甸等国家的商家就提供过微信小程序。这些商家开通小程序&#xff0c;为本地的华人提供服务。但通常小程序的开发者/服务商位于中国&#xff…

TCP/IP(十四)流量控制

一 流量控制 说明&#xff1a; 本文只是原理铺垫,没有用tcpdumpwiresahrk鲜活的案例讲解,后续补充 ① 基本概念 流量控制: TCP 通过接受方实际能接收的数据量来控制发送方的窗口大小 ② 正常传输过程 背景:1、客户端是接收方,服务端是发送方 --> 下载2、假设接收窗…