Python - 深夜数据结构与算法之 Binary Search

目录

一.引言

二.二分查找的简介

1.查找条件

2.代码模版

3.查找示例

三.经典算法实战

1.Search-Rotated-List [33]

2.Sqrt-X [69]

3.Search-2D-Matrix [74]

4.Find-Rotated-Min [153]

5.Valid-Perfect-Square [367]

四.总结


一.引言

前面介绍了二叉树和堆,其中涉及到有树和二叉搜索的概念,今天将二者整合介绍下常见的二分查找的问题。

二.二分查找的简介

1.查找条件

单调性 - 如果对应数据不具有单调性性质,则我们只能 o(n) 遍历寻找

上下界 - 存在上下界才能不断缩小范围

索引访问 - 列表可以,单链表的话不支持索引访问不容易二分

2.代码模版

right、left 即为我们的上下界,通过 mid 每次将搜索范围减半,时间复杂度为 log。代码模版中我们默认是升序排列的,如果是降序排序需要修改下elif 和 else 的逻辑,我们主要掌握上面的模版,即 left、rigth 的起始点,如何获取 mid 并判断。

3.查找示例

 数组满足有序、有界、索引访问所以可以进行二分查找,不断寻找 mid 缩小 left、right 的范围,就像高数里求数学极限的夹逼准则一样,直到找到 target 或者退出。

三.经典算法实战

1.Search-Rotated-List [33]

搜索旋转排序数组: https://leetcode.cn/problems/search-in-rotated-sorted-array

题目分析

对一个旋转后的有序数组进行排序,最暴力的方法无非 o(n) 遍历,找到突变的 index,即前后元素不保序,随后将数组恢复为有序再 sort,这个方法是最基础的,不过这里也可以套用二分查找的模版,只不过判断的边界条件会复杂一些,下面尝试下。

二分查找

class Solution(object):def search(self, nums, target):""":type nums: List[int]:type target: int:rtype: int"""left, right = 0, len(nums) - 1while left <= right:mid = (left + right) // 2# 找到了if nums[mid] == target:return midif nums[0] <= nums[mid]: # 左边数组有序 [4,5,6,7,0,1,2]if nums[0] <= target < nums[mid]:right = mid - 1else:left = mid + 1 else: # 右边数组有序 [6,7,0,1,2,4,5]if nums[mid] < target <= nums[len(nums) - 1]:left = mid + 1else:right = mid - 1return -1

这个题要求给出 log(n) 的解法,所以暴力求解是不行的,考虑使用二分查找主要需要明确一个点就是不管数组怎么分,它的左右两边一定是有一边有序的,我们只需要每次二分找有序的那一部分判断 target 在不在即可,不在就去另一边再找。因为 nums[mid] != target,所以两个有序区间都是一开一闭,左边为 '[)' 右边为 '(]'。

2.Sqrt-X [69]

X 的平方根: https://leetcode.cn/problems/sqrtx/description/

题目分析

此题可以使用二分,我们看下三要素是否满足: 

- 单调性  x^2 函数是单调的

- 有界 对于 x 的平方根而言,其一定在 0-x 之间,有界

- 索引 这个这里不需要了,我们使用 o(1) 的内存就解决了

 二分查找

class Solution(object):def mySqrt(self, x):""":type x: int:rtype: int"""# 左右界left, right = 0, xwhile left <= right:# 取整mid = (left + right) // 2if x >= mid * mid:left = mid + 1else:right = mid - 1return right

如果平方根 re^2 = x,则其整数部分一定满足 x >= int(re)^2。再解释下最后为什么返回 right,这里其实返回 left - 1 也一样,这是因为我们的 x 的平方根一定满足:

 re^2 <= x < (re+1)^2

当我们最后一次计算到 mid = (re+1) 时,此时进入 else 逻辑,left = re + 1,right = re,再次计算已经不满足 left <= right 的逻辑了,此时返回 right 或者 left - 1 都是返回 re。

3.Search-2D-Matrix [74]

搜索二维矩阵: https://leetcode.cn/problems/search-a-2d-matrix

题目分析

给定从左到右递增的二维矩阵,求目标 target 是否存在,这题第一反应我们可以直接将 Matrix Flatten 打平为 1D 的 Array 再执行二分查找即可,还有一种就是分别在列和行上做二分查找,先找到对应行,再找到对应列里是否存在。

暴力二分查找

class Solution(object):def searchMatrix(self, matrix, target):""":type matrix: List[List[int]]:type target: int:rtype: bool"""# 各种边界条件if not matrix:return Falseif target < matrix[0][0] or target > matrix[len(matrix) - 1][len(matrix[0]) - 1]:return Falsenums = [][nums.extend(i) for i in matrix]# 寻找对应行left, right = 0, len(nums) - 1while left <= right:mid = (left + right) // 2if nums[mid] == target:return Trueif nums[mid] > target:right = mid - 1else:left = mid + 1return False

先 extend 再二分查找,这样遍历的是 o(mxn),如果只遍历行与列,则是 o(m + n)。

 

精简二分查找

class Solution(object):def searchMatrix(self, matrix, target):""":type matrix: List[List[int]]:type target: int:rtype: bool"""# 各种边界条件if not matrix:return Falseif target < matrix[0][0] or target > matrix[len(matrix) - 1][len(matrix[0]) - 1]:return False# 寻找对应行col_nums = [row[0] for row in matrix]left, right = 0, len(col_nums) - 1while left <= right:mid = (left + right) // 2if col_nums[mid] == target:return Trueif col_nums[mid] > target:right = mid - 1else:left = mid + 1# 在对应行操作row_nums = matrix[right]left, right = 0, len(row_nums) - 1while left <= right:mid = (left + right) // 2if row_nums[mid] == target:return Trueif row_nums[mid] > target:right = mid - 1else:left = mid + 1return False

先找 col_nums 找到 target 应该在哪一行,再找 target 在不在 row_nums 里。

4.Find-Rotated-Min [153]

旋转排序最小值: https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array

题目分析

二分查找的本质其实是通过条件缩小每次的检查范围,本题的思路直接想比较麻烦,在记事本上写一下会方便很多,这里我们二分的条件就是找小的在哪,无非左边或右边,所以我们直接列举全部情况即可。

二分查找

class Solution(object):def findMin(self, nums):""":type nums: List[int]:rtype: int"""# 完全有序if nums[0] <= nums[-1]:return nums[0]left, right = 0, len(nums) - 1# 找哪边小,去小的那边接着找while left <= right:if nums[left] == nums[right]:return nums[left]mid = (left + right) // 2# [2, 3, 4, 5, 1] 中间比左边大 -> 右边if nums[mid] >= nums[0]:left = mid + 1# [5, 1, 2, 3, 4] 中间比左边小 -> 左边else:right = midreturn nums[left]

nums[0] <= nums[-1]  完全有序,直接出第一个最小的

nums[mid] >= nums[0] 左边有序,最小值在右边 left = mid + 1

nums[mid] < nums[0] 最小值在左边,结合在中间的特殊情况 right = mid

5.Valid-Perfect-Square [367]

有效的完全平方数: https://leetcode-cn.com/problems/valid-perfect-square/

题目分析

找平方的题目,起始就是找到 re ^^ 2 <= num < (re+1) ^^ 2,此时 left = re+1,right = re,因为我们判断是否是完全平方,所以判断 re ^^ 2 == num 即可。

二分查找 

class Solution(object):def isPerfectSquare(self, num):""":type num: int:rtype: bool"""left, right = 0, numwhile left <= right:mid = (left + right) // 2if num >= mid * mid:left = mid + 1else:right = mid - 1return right ** 2 == num

直接看是否是 int(re) 的平方即可。

 

四.总结

二分查找的核心思路是根据优先级关系进行搜索区间的缩小,由于其主要就向左和向右两种情况,很多时候没思路可以直接在纸上把几种情况罗列一下再分析,会更容易上手一些。至于一些 < 还是 <=,+1 还是 -1 可以多调试几次,最后理解含义。

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

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

相关文章

【Vue2+3入门到实战】(12)自定义指令的基本语法(全局、局部注册)、 指令的值、v-loading的指令封装 详细示例

目录 一、学习目标1.自定义指令 二、自定义指令1.指令介绍2.自定义指令3.自定义指令语法4.指令中的配置项介绍5.代码示例6.总结 三、自定义指令-指令的值1.需求2.语法3.代码示例 四、自定义指令-v-loading指令的封装1.场景2.需求3.分析4.实现5.准备代码 六、自定义指令总结 一、…

修改jenkins的目录(JENKINS_HOME)

默认JENKINS_HOME是/var/lib/jenkins/ 现要修改为/home/jenkins_data/jenkins 最开始 sudo cp -a /var/lib/jenkins/ /home/jenkins_data/ 然后如下操作&#xff1a; 1、首先 /etc/sysconfig/jenkins&#xff1a;jenkins配置文件&#xff0c;“端口”&#xff0c;“JENKIN…

【占用网络】OccNet: Scene as Occupancy 适用于检测、分割和规划任务 ICCV2023

前言 本文分享“占用网络”方案中&#xff0c;具有代表性的方法&#xff1a;OccNet。 它以多视角相机为核心&#xff0c;首先生成BEV特征&#xff0c;然后通过级联结构和时间体素解码器重建生成3D占用特征。 构建一个通用的“3D占用编码特征”&#xff0c;用以表示3D物理世界…

2023-12-29 服务器开发-centos-安装php8

摘要: 2023-12-29 服务器开发-centos-安装php8 centos-安装php8 必备条件 Minimal CentOS 8 / RHEL 8User with sudo rightsInternet Connection (1) 更新系统 更新系统 $ sudo dnf update $ sudo dnf upgrade 重启系统 $ sudo reboot (2) 启用 EPEL & Remi 软件库…

Starling-LM-7B与GPT-4:开源AI的新纪录

引言 在人工智能的前沿领域&#xff0c;Starling-LM-7B的出现标志着开源大型语言模型&#xff08;LLM&#xff09;的一大突破。与GPT-4的近距离竞争不仅展示了Starling-LM-7B的技术实力&#xff0c;也突显了开源社区在推动AI发展方面的重要作用。 模型特点 Starling-LM-7B&a…

HTML使用JavaScript的三种方式

要使用 JavaScript&#xff0c;你可以在 HTML 文件中的 <script> 标签中编写代码&#xff0c;或者将代码保存到一个单独的 .js 文件中并在 HTML 文件中引入。以下是一些常用的 JavaScript 使用方式&#xff1a; 内联 JavaScript&#xff1a;在 HTML 文件的 <script&g…

【电子通识】开关的种类

开关在我们日常生活与工作中使用较多。开关有无数种形式&#xff0c;种类繁多。从微小的按钮到巨大的控制器&#xff0c;功能多种多样。这种多样性受到机械或电气操作、手动或电子控制等因素的影响&#xff0c;并且与个人在设计美学和用户界面方面的偏好也有关。 电子开关采用 …

mysql查询出json格式字段中的值

一、使用场景 由于一些特殊数据使用json格式保存到表数据种中了&#xff0c;在查询的时候需要查询出这条数据中json格式中的某个字段 比如&#xff1a;需要将下列字符串中的“nationality”字段单独查询出来 json格式是一个对象 结果&#xff1a; json格式是一个集合 查询结…

第三章 Zookeeper服务注册与发现

Zookeeper服务注册与发现 gitee&#xff1a;springcloud_study: springcloud&#xff1a;服务集群、注册中心、配置中心&#xff08;热更新&#xff09;、服务网关&#xff08;校验、路由、负载均衡&#xff09;、分布式缓存、分布式搜索、消息队列&#xff08;异步通信&#…

泛目录是干什么用的蚂蚁seo泛程序

泛目录是干什么用的蚂蚁seo泛程序目录 泛目录是一种常见的网站优化方法&#xff0c;属于黑帽技术的一种。它的核心原理是利用高权重的网站继承目录&#xff0c;然后快速获得收录与排名。这种方法可以帮助网站在搜索引擎中获得更好的排名&#xff0c;从而吸引更多的流量。 泛目…

C++面试宝典第11题:两数之和

题目 给定一个整数数组和一个目标值,请在该数组中找出和为目标值的那两个整数,并返回他们的数组下标,要求时间复杂度为O(n)。可以假设每种输入只会对应一个答案,注意:不能重复利用这个数组中同样的元素。 解析 这道题主要考察应聘者对算法时间复杂度和空间复杂度的理解,时…

“踩坑”经验分享:Swift语言落地实践

作者 | 路涛、艳红 导读 Swift 是一种适用于iOS/macOS应用开发、服务器端的编程语言。自2014年苹果发布 Swift 语言以来&#xff0c;Swift5 实现了 ABI 稳定性、Module 稳定性和Library Evolution&#xff0c;与Objective-C&#xff08;下文简称“OC”&#xff09;相比&#xf…

边缘智能网关在智慧大棚上的应用突破物联网大关

边缘智能网关在智慧大棚上的应用&#xff0c;是现代农业技术的一大突破。通过与农作物生长模型的结合&#xff0c;边缘智能网关可以根据实时的环境数据和历史数据&#xff0c;预测农作物的生长趋势和产量&#xff0c;提供决策支持和优化方案。这对于农民来说&#xff0c;不仅可…

算法学习系列(十五):最小堆、堆排序

目录 引言一、最小堆概念二、堆排序模板&#xff08;最小堆&#xff09;三、模拟堆 引言 这个堆排序的话&#xff0c;考的还挺多的&#xff0c;主要是构建最小堆&#xff0c;并且在很多情况下某些东西还用得着它来优化&#xff0c;比如说迪杰斯特拉算法可以用最小堆优化&#…

软件测试/测试开发丨学习笔记之Python运算符

运算符的作用 Python基础语法的内容通常表示不同数据或变量之间的关系 算数运算符 运算符描述加-减*乘/除%取模**幂//取整除 取模与取余区别 概念上&#xff1a;取模是计算机术语&#xff0c;取余属于数学概念&#xff1b; 结果上&#xff1a;当同号的两个数相除&#xff…

【北亚服务器数据恢复】ZFS文件系统服务器ZPOOL下线的数据恢复案例

服务器数据恢复环境&#xff1a; 服务器中有32块硬盘&#xff0c;组建了3组RAIDZ&#xff0c;部分磁盘作为热备盘。zfs文件系统。 服务器故障&#xff1a; 服务器运行中突然崩溃&#xff0c;排除断电、进水、异常操作等外部因素。工作人员将服务器重启后发现无法进入操作系统。…

CData ADO.NET Data Providers 2022 Crack

ADO.NET 数据提供程序 轻松将 .NET 应用程序与 SaaS、NoSQL 和大数据连接起来 数据绑定到应用程序、数据库和服务 完整的创建、读取、更新和删除 (CRUD) 支持&#xff0c;无需编码 200 基于标准的 ADO.NET 数据提供程序 100% 适用于 .NET Standard、.NET Core 和 Xamarin 的完全…

低成本高效率易部署,Ruff工业数采网关+IoT云平台赋能工厂数字化管理

随着工业4.0的快速发展&#xff0c;工业物联网是工业企业实现数字化转型的重要助力&#xff0c;物联网技术的应用也越来越广泛。 作为连接设备与网络的关键节点&#xff0c;数据采集网关是连接工业设备与物联网平台的硬件设备&#xff0c;它负责将工业设备的数据采集、传输到物…

Vite+Vue3学习笔记(2)——语法、渲染、事件、数据传递、生命周期、第三方库、前端部署

官网链接&#xff1a;https://cn.vuejs.org/ 如果出现普通用户无法新建项目&#xff0c;必须要管理员身份新建&#xff0c;那么可以在nodejs的安装路径设置安全选项&#xff0c;提高普通用户的权限。 具体方法参考&#xff1a; https://blog.csdn.net/weixin_43174650/article/…

助力城市部件[标石/电杆/光交箱/人井]精细化管理,基于YOLOv6开发构建生活场景下城市部件检测识别系统

井盖、店杆、光交箱、通信箱、标石等为城市中常见部件&#xff0c;在方便居民生活的同时&#xff0c;因为后期维护的不及时往往会出现一些“井盖吃人”、“线杆、电杆、线缆伤人”事件。造成这类问题的原因是客观的多方面的&#xff0c;这也是城市化进程不断发展进步的过程中难…