【算法优选】 二分查找专题——贰

文章目录

  • 😎前言
  • 🌲[山脉数组的峰顶索引](https://leetcode.cn/problems/peak-index-in-a-mountain-array/)
    • 🚩题目描述:
    • 🚩算法思路
    • 🚩代码实现:
  • 🌴[寻找峰值](https://leetcode.cn/problems/find-peak-element/submissions/)
    • 🚩题目描述
    • 🚩算法思路:
    • 🚩代码实现
  • 🍀[寻找旋转排序数组中的最小值](https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array/)
    • 🚩题目描述
    • 🚩算法思路
    • 🚩代码实现
  • 🎍[点名](https://leetcode.cn/problems/que-shi-de-shu-zi-lcof/)
    • 🚩题目描述
    • 🚩思路解析
    • 🚩代码实现
  • ⭕总结

😎前言

二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列

查找过程

首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。

算法要求

1.必须采用顺序存储结构。
2.必须按关键字大小有序排列。

比较次数

计算公式:
当顺序表有n个关键字时:
查找失败时,至少比较a次关键字;
查找成功时,最多比较关键字次数是b。
注意:a,b,n均为正整数。

算法复杂度

二分查找的基本思想是将n个元素分成大致相等的两部分,取a[n/2]与x做比较,如果x=a[n/2],则找到x,算法中止;如果x<a[n/2],则只要在数组a的左半部分继续搜索x,如果x>a[n/2],则只要在数组a的右半部搜索x.
时间复杂度即是while循环的次数。
总共有n个元素,
渐渐跟下去就是n,n/2,n/4,…n/2^k(接下来操作元素的剩余个数),其中k就是循环的次数
由于你n/2^k取整后>=1
即令n/2^k=1
可得k=log2n,(是以2为底,n的对数)
所以时间复杂度可以表示O(h)=O(log2n)

🌲山脉数组的峰顶索引

🚩题目描述:

符合下列属性的数组 arr 称为 山脉数组 :
arr.length >= 3
存在 i(0 < i < arr.length - 1)使得:

  • arr[0] < arr[1] < … arr[i-1] < arr[i]

  • arr[i] > arr[i+1] > … > arr[arr.length - 1]

给你由整数组成的山脉数组 arr ,返回满足 arr[0] < arr[1] < … arr[i - 1] < arr[i] > arr[i + 1] > … > arr[arr.length - 1] 的下标 i 。

你必须设计并实现时间复杂度为 O(log(n)) 的解决方案。

  • 示例 1:
    输入:arr = [0,1,0]
    输出:1

  • 示例 2:
    输入:arr = [0,2,1,0]
    输出:1

  • 示例 3:
    输入:arr = [0,10,5,2]
    输出:1

class Solution {public int peakIndexInMountainArray(int[] arr) {}
}

🚩算法思路

1、分析峰顶位置的数据特点,以及⼭峰两旁的数据的特点:

  • 峰顶数据特点: arr[i] > arr[i - 1] && arr[i] > arr[i + 1] ;

  • 峰顶左边的数据特点: arr[i] > arr[i - 1] && arr[i] < arr[i + 1] ,也就是呈现上升趋势

  • 峰顶右边数据的特点: arr[i] < arr[i - 1] && arr[i] > arr[i + 1] ,也就是呈现下降趋势

2.、因此,根据 mid 位置的信息,我们可以分为下⾯三种情况:

  • 如果 mid 位置呈现上升趋势,说明我们接下来要在 [mid + 1, right] 区间继续搜索;

  • 如果 mid 位置呈现下降趋势,说明我们接下来要在 [left, mid - 1] 区间搜索;

  • 如果 mid 位置就是⼭峰,直接返回结果

🚩代码实现:

class Solution {public int peakIndexInMountainArray(int[] arr) {int left = 1;int right = arr.length - 2;while(left < right) {int mid = left + (right - left + 1) / 2;if(arr[mid] > arr[mid - 1]) {left = mid;} else {right = mid - 1;}}return left;}
}

🌴寻找峰值

🚩题目描述

峰值元素是指其值严格大于左右相邻值的元素。

给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。

你可以假设 nums[-1] = nums[n] = -∞ 。

你必须实现时间复杂度为 O(log n) 的算法来解决此问题。

  • 示例 1:
    输入:nums = [1,2,3,1]
    输出:2
    解释:3 是峰值元素,你的函数应该返回其索引 2。
  • 示例 2:
    输入:nums = [1,2,1,3,5,6,4]
    输出:1 或 5
    解释:你的函数可以返回索引 1,其峰值元素为 2;或者返回索引 5, 其峰值元素为 6。
class Solution {public int findPeakElement(int[] nums) {}
}

🚩算法思路:

寻找⼆段性:
任取⼀个点 i ,与下⼀个点 i + 1 ,会有如下两种情况:

  1. arr[i] > arr[i + 1] :此时「左侧区域」⼀定会存在⼭峰(因为最左侧是负⽆穷),那么我们可以去左侧去寻找结果;

  2. arr[i] < arr[i + 1] :此时「右侧区域」⼀定会存在⼭峰(因为最右侧是负⽆穷),那么我们可以去右侧去寻找结果

当我们找到「⼆段性」的时候,就可以尝试⽤「⼆分查找」算法来解决问题

🚩代码实现

class Solution {public int findPeakElement(int[] nums) {int left = 0;int right = nums.length - 1;if(right < 1) {return 0;}while(left < right) {int cmd = (left + right + 1) / 2;if(nums[cmd -1] <= nums[cmd] ) {left = cmd;} else {right = cmd -1;}}return left;}
}

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

🚩题目描述

已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:

  • 若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
  • 若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]

注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。

给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

  • 示例 1:
    输入:nums = [3,4,5,1,2]
    输出:1
    解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。

  • 示例 2:
    输入:nums = [4,5,6,7,0,1,2]
    输出:0
    解释:原数组为 [0,1,2,4,5,6,7] ,旋转 4 次得到输入数组。

  • 示例 3:
    输入:nums = [11,13,15,17]
    输出:11
    解释:原数组为 [11,13,15,17] ,旋转 4 次得到输入数组

class Solution {public int findMin(int[] nums) {}
}

🚩算法思路

题⽬中的数组规则如下图所⽰:
在这里插入图片描述
其中 C 点就是我们要求的点。

⼆分的本质:找到⼀个判断标准,使得查找区间能够⼀分为⼆。

通过图像我们可以发现, [A,B] 区间内的点都是严格⼤于 D 点的值的, C 点的值是严格⼩于 D 点的值的。但是当 [C,D] 区间只有⼀个元素的时候, C 点的值是可能等于 D 点的值的。

因此,初始化左右两个指针 left , right :

然后根据 mid 的落点,我们可以这样划分下⼀次查询的区间:

  • 当 mid 在 [A,B] 区间的时候,也就是 mid 位置的值严格⼤于 D 点的值,下⼀次查询区间在 [mid + 1,right] 上;
  • 当 mid 在 [C,D] 区间的时候,也就是 mid 位置的值严格⼩于等于 D 点的值,下次

查询区间在 [left,mid] 上。

当区间⻓度变成 1 的时候,就是我们要找的结果

🚩代码实现

class Solution {public int findMin(int[] nums) {int left = 0;int right = nums.length - 1;int cmp = nums[right];while(left < right) {int cmd = (left + right ) / 2;if(nums[cmd] > cmp) {left = cmd + 1;} else {right = cmd;}}return nums[left];}
}

🎍点名

🚩题目描述

某班级 n 位同学的学号为 0 ~ n-1。点名结果记录于升序数组 records。假定仅有一位同学缺席,请返回他的学号。

  • 示例 1:
    输入: records = [0,1,2,3,5]
    输出: 4

  • 示例 2:
    输入: records = [0, 1, 2, 3, 4, 5, 6, 8]
    输出: 7

🚩思路解析

关于这道题中,时间复杂度为 O(N) 的解法有很多种,⽽且也是⽐较好想的,这⾥就不再赘述。

本题只讲解⼀个最优的⼆分法,来解决这个问题。
在这个升序的数组中,我们发现:

  • 在第⼀个缺失位置的左边,数组内的元素都是与数组的下标相等的;

  • 在第⼀个缺失位置的右边,数组内的元素与数组下标是不相等的。

因此,我们可以利⽤这个「⼆段性」,来使⽤「⼆分查找」算法。

🚩代码实现

class Solution {public int missingNumber(int[] nums) {int left = 0;int right = nums.length - 1;while(left < right) {int mid = left + (right - left) / 2;if(nums[mid] == mid) {left = mid + 1;} else {right = mid;}}return left == nums[left] ? left + 1 : left;}
}

⭕总结

关于《【算法优选】 二分查找专题——贰》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下!

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

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

相关文章

Oracle 简介与 Docker Compose部署

最近&#xff0c;我翻阅了在之前公司工作时的笔记&#xff0c;偶然发现了一些有关数据库的记录。当初&#xff0c;我们的项目一开始采用的是 Oracle 数据库&#xff0c;但随着项目需求的变化&#xff0c;我们不得不转向使用 SQL Server。值得一提的是&#xff0c;公司之前采用的…

golang使用energy开发GUI桌面程序,CEF,LCL

1、概述 仓库&#xff1a;https://github.com/energye/energy 文档&#xff1a;https://energy.yanghy.cn/ Energy 是 Go 基于 CEF(Chromium Embedded Framework) 开发的框架&#xff0c;内嵌 CEF 二进制 使用 Go 和 Web 端技术 ( HTML CSS JavaScript ) 构建支持Windows, …

MongoDB——centOS7环境Mongodb权限管理(图解版)

目录 一、MongDB权限概述1.1、MongDB权限概述1.2、MongDB权限列表 二、Mongodb权限管理示例2.1、创建账号2.1.1、创建管理员用户2.1.2、开启认证2.1.3、创建普通账号 一、MongDB权限概述 1.1、MongDB权限概述 mongodb是没有默认管理员账号&#xff0c;所以要先添加管理员账号…

解决echarts配置滚动(dataZoom)后导出图片数据不全问题

先展现一个echarts&#xff0c;并配置dataZoom&#xff0c;每页最多10条数据&#xff0c;超出滚动 <div class"echartsBox" id"echartsBox"></div>onMounted(() > {nextTick(() > {var chartDom document.getElementById(echartsBox);…

ROS仿真软件Turtlebot-Gazebo的安装使用以及错误处理[机器人避障]

很多时候由于机器人价格比较贵&#xff0c;而且会因为环境因素、操作失误或者摔坏等&#xff0c;所以我们可以先在仿真软件上做测试&#xff0c;也可以避免这些问题&#xff0c;虽然没有那么真实感&#xff0c;可毕竟是免费的嘛。我们可以在这些仿真的机器人身上去学习如何控制…

Java使用opencv实现人脸识别、人脸比对

1. opencv概述 OpenCV是一个开源的计算机视觉库&#xff0c;它提供了一系列丰富的图像处理和计算机视觉算法&#xff0c;包括图像读取、显示、滤波、特征检测、目标跟踪等功能。 opencv官网&#xff1a;https://opencv.org/ opencv官网文档&#xff1a;https://docs.opencv.or…

Spring三级缓存流程再梳理

本文主要是说下在使用spring时遇到了循环依赖&#xff0c;Spring利用三级缓存怎么解决 getBean(beanName)doGetBean(name, null, null, false);getSingleton(beanName)方法&#xff0c; 最后会通过addSingleton(beanName, singletonObject)存到一级缓存里面去createBean(beanN…

一文拿捏对象内存布局及JMM(JAVA内存模型)

1 JMM(Java Memory Model) 1 概述 Java内存模型(Java Memory Model简称JMM)是一种抽象的概念&#xff0c;并不真实存在&#xff0c;它描述的一组规则或者规范。通过这些规则、规范定义了程序中各个变量的访问方式。jvm运行的程序的实体是线程&#xff0c;而每个线程运行时&am…

Unity编辑器从PC平台切换到Android平台下 Addressable 加载模型出现粉红色,类似于材质丢失的问题

Unity编辑器在PC平台下使用Addressable加载打包好的Cube&#xff0c;运行发现能正常显示。 而在切换到Android平台下&#xff0c;使用Addressable时加载AB包&#xff0c;生成Cube对象时&#xff0c;Cube模型呈现粉红色&#xff0c;出现类似材质丢失的问题。如下图所示。 这是…

安全设备和防火墙

文章目录 微步TDP态势感知防火墙防火墙的负载均衡 微步TDP态势感知 安全设备的主要功能在黑名单&#xff0c;只要记住黑名单的功能在哪即可 常用的是威胁选项卡的监控功能&#xff0c;监控模块会把实时的告警列出来&#xff0c;只要列出来就能分析流量是误报还是真实的&#x…

tomcat服务tomcat多实例部署

tomcat服务&&tomcat多实例部署 文章目录 tomcat服务&&tomcat多实例部署1.简介2.优缺点优点&#xff1a;缺点&#xff1a; 3.工作原理4.工作流程5.tomcat服务部署5.1.java环境安装5.2.拉取tomcat软件包5.3.解压部署5.4.启动tomcat服务5.5.访问tomcat的web页面5.…

基于VUE的图书借阅管理系统的设计与实现

目录 一、摘要 二、技术描述 三、部分截图 四、获取方式 一、摘要 随着我国经济的高速发展&#xff0c;人们对图书的需求也愈发旺盛&#xff0c;而传统图书管理模式存在以下弊端&#xff1a;信息存储和分类操作不够高效&#xff0c;导致查找书籍困难&#xff1b;借还书流程…

【数据结构-栈 二】【单调栈】每日温度、接雨水

废话不多说&#xff0c;喊一句号子鼓励自己&#xff1a;程序员永不失业&#xff0c;程序员走向架构&#xff01;本篇Blog的主题是【单调栈的应用】&#xff0c;使用【栈】这个基本的数据结构来实现&#xff0c;这个高频题的站点是&#xff1a;CodeTop&#xff0c;筛选条件为&am…

location rewrite

Nginx location 匹配的规则和优先级 Nginx常用的变量 rewrite: 重定向功能 Location 匹配 URI URI&#xff1a;统一资源的表示符&#xff0c;是一种字符串标识&#xff0c;用于标识抽象或者物理资源 先来巩固一些与location结合使用的正则表达式 正则表达式&#xff1a;匹…

基于安卓android微信小程序音乐播放器

运行环境 小程序前端框架&#xff1a;uniapp 小程序运行软件&#xff1a;微信开发者 后端技术:javaSsm(SpringSpringMVCMyBatis)vue.js 后端开发环境:idea/eclipse 数据库:mysql 项目介绍 音乐播放器小程序的设计主要是对系统所要实现的功能进行详细考虑&#xff0c;确定所要…

【机器学习 | 回归问题】超越直线:释放多项式回归的潜力 —— 详解线性回归与非线性 (含详细案例、源码)

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

【数据结构-字符串 四】【字符串识别】字符串转为整数、比较版本号

废话不多说&#xff0c;喊一句号子鼓励自己&#xff1a;程序员永不失业&#xff0c;程序员走向架构&#xff01;本篇Blog的主题是【字符串转换】&#xff0c;使用【字符串】这个基本的数据结构来实现&#xff0c;这个高频题的站点是&#xff1a;CodeTop&#xff0c;筛选条件为&…

Java Day1

day01 一、Markdown 基础语法1.标题2. 字体3. 引用 >4. 分隔线 --- ***5. 图片 ![]()6.超链接7.列表8.表格9.代码 代码名称 二、计算机三、常用快捷键1. Win 系列2. Ctrl 系列3. ALt 系列 四、 基本的DOS命令1. 打开方式&#xff1a;2. 常用DOS命令 五、计算机语言发展史第一…

【软件测试学习】—软件测试知识点总结(二)

【软件测试学习】—软件测试的分类&#xff08;二&#xff09; 一、软件测试的分类 二、软件的生命周期 三、软件测试的工作流程 四、软件测试用例设计方法 &#xff08;一&#xff09;、等价类划分 定义&#xff1a;等价类划分是一种典型的、重要的黑盒测试的方法&#xff…

从零开始探索C语言(十一)----共用体和位域

文章目录 1. 共用体1.1 定义共用体1.2 访问共用体成员 2. 位域2.1 位域声明2.2 位域的定义和位域变量的说明2.3 位域的使用2.4 位域小结 1. 共用体 共用体是一种特殊的数据类型&#xff0c;允许您在相同的内存位置存储不同的数据类型。您可以定义一个带有多成员的共用体&#…