算法入门-二分搜索(长期更新)

文章目录

      • 情景一 : 二分查找
      • 情景二 : 找出一个 >= num 的最左侧的位置
      • 情景三 : 找出一个 <= num 的最右侧的位置
      • leetcode 162 :寻找峰值
      • leetcode 69 : x 的平方根

首先来简介一下二分搜索算法,二分搜索是一种每次砍半的算法,最经典的案例当然是我们的二分查找算法,但是大部分人所认知的二分搜索都是必须要满足这个 数组有序,才可以进行,其实不然,二分的本质逻辑是建立在"砍半",而砍半的本质就是你知道那一半一定没有,而另一半不一定有的前提下,只要满足了这一前提条件,那么你就可以尽可以进行二分…这个算法的时间复杂度是O(logN)
我们这个算法的系列将会长期更新,在遇见好题了之后就会加进来进行整理

情景一 : 二分查找

这个是二分最经典的情景,也就是在一个数组中进行每次砍半的查找元素
代码实现如下

public static int myBinarySearch(int[] nums,int key){if(nums == null || nums.length == 0){System.out.println("无法进行搜索");return -1;}int left = 0;int right = nums.length - 1;int mid;while(left <= right){//请注意这里我们对于我们这个平均值的处理情况mid = left + ((right - left)>>1);if(nums[mid] > key){right = mid - 1;}else if(nums[mid] < key){left = mid + 1;}else{return mid;}}return -1;}

注意一下我们这里的求其平均值的操作,是利用位运算,其一是防止其溢出,其二是加快运算的速度,因为位运算的速度要远大于除法运算…

情景二 : 找出一个 >= num 的最左侧的位置

这个其实也是二分的逻辑,我们定义一个标记物 ans 初始化置为-1,当我们的mid满足条件的时候,我们就将我们的ans置为 mid ,然后继续二分,当不满足条件的时候,我们就不进行操作,继续二分,然后最后返回我们的 ans 标记物…
代码实现如下 :

/***      情景二 : 找到 >= num 的最左侧的位置*      这个基本的逻辑跟二分搜索法其实是一致的,但是也是有一定的差别,比如这个必须要搜索彻底才可以*      当每次满足条件的时候,就进行 ans 的更新...直到left == right;**      可能你有疑问:为什么我们不进行 <= num 的最左侧位置的查找 ...*      因为这个问题是没有意义的..因为只需要判断 nums[0] 跟 key的关系* @param nums : 待搜索的数组* @param key : 待定的查找元素* @return*/public static int findNumMaxLeft(int[] nums,int key){if(nums == null || nums.length == 0){System.out.println("无法进行搜索");return -1;}int left = 0;int right = nums.length - 1;int mid;int ans = -1;while(left <= right){mid = left +((right - left) >> 1);if(nums[mid] >= key){ans = mid;right = mid - 1;}else if(nums[mid] < key){left = mid + 1;}}return ans;}

情景三 : 找出一个 <= num 的最右侧的位置

这个其实跟情景二是对称的,原理是一致的,当满足条件的时候记录下来继续进行二分,当不满足条件的时候不进行记录然后继续进行二分,到二分到不能再次进行二分的情况之后,就返回我们的标记ans值…
代码实现如下:

public static int findNumMinRight(int[] nums,int key){if(nums == null || nums.length == 0){System.out.println("无法进行搜索");return -1;}int left = 0;int right = nums.length - 1;int mid;int ans = -1;while(left <= right){mid = left +((right - left) >> 1);if(nums[mid] <= key){left = mid + 1;ans = mid;}else if(nums[mid] > key){right = mid - 1;}}return ans;}

leetcode 162 :寻找峰值

在这里插入图片描述
首先我们来分析一下这个题干,这个数组中相邻的两个元素都是不相等的,然后让你返回其中的一个峰值(任意一个就可以),那这道题为什么可以进行二分呢…,我们来看体重的假设提示,我们假设 nums[-1] 和 nums[n] 都是 负无穷
首先我们判断一下特殊的情况,假设我们的 第一个元素大于第二个元素,所以此时第一个元素就是局部的峰值(其实这里有点类似函数极值点的概念),对应的如果最后一个元素要大于倒数第二个元素,那么最后一个元素就是峰值

特殊情况的制约if(nums == null || nums.length == 0){System.out.println("这个数组不可能存在峰值");return -1;}//下面都是一些特殊情况的判断...(端点处的极值问题)if(nums.length == 1){return 0;}if(nums[0] > nums[1]){return 0;}if(nums[nums.length-1] > nums[nums.length - 2]){return nums.length - 1;}

下面我们进行一般情况的分析
在这里插入图片描述
我们现在不满足特殊条件,所以我们数组的走向是这样的,那么因为我的开头处是上升,终点位置是下降,所以中间的某个位置一定存在至少一个极值点(有点类似中值定理) 所以我们可以进行二分
判断nums[mid] 和 nums[mid-1] 与nums[mid+1] 之间的关系…
而中值位置情况的只有以下四种
在这里插入图片描述
其中 1 2 4 都不是我们所需要的,所以要继续进行二分搜索
所以我们可以写出如下的代码

int left = 1;int right = nums.length - 2;int mid;/*** 注意:* 这里的控制条件其实非常合理,在中点处一共只有四种情况,而这个循环的控制体系可以控制其中的三种无峰值的情况...*/while(left <= right){mid = left +((right - left) >> 1);if(nums[mid] < nums[mid - 1]){right = mid - 1;}else if(nums[mid] < nums [mid + 1]){left = mid + 1;}else{return mid;}}return -1;

下面是我们的完整代码

public static int findPeakNumber(int[] nums){if(nums == null || nums.length == 0){System.out.println("这个数组不可能存在峰值");return -1;}//下面都是一些特殊情况的判断...(端点处的极值问题)if(nums.length == 1){return 0;}if(nums[0] > nums[1]){return 0;}if(nums[nums.length-1] > nums[nums.length - 2]){return nums.length - 1;}//下面是普通的一个情况//其实有点类似数学的拉格朗日中值定理int left = 1;int right = nums.length - 2;int mid;/*** 注意:* 这里的控制条件其实非常合理,在中点处一共只有四种情况,而这个循环的控制体系可以控制其中的三种无峰值的情况...*/while(left <= right){mid = left +((right - left) >> 1);if(nums[mid] < nums[mid - 1]){right = mid - 1;}else if(nums[mid] < nums [mid + 1]){left = mid + 1;}else{return mid;}}return -1;}

leetcode 69 : x 的平方根

在这里插入图片描述
这就是一个典型的可以进行二分的题
这个题的核心逻辑跟我们第三个题 : 找出 >= num 的最右侧位置是一致的
值得一提的是,我们这个题要控制我们的算数范围,否则就会出现溢出的问题,下面就是我们的代码解析…没啥可说的了

/***  找出一个数的算术平方根向下取证的那个数然后返回* @param x : 待定的开方数* @return*/public static int mySqrt(int x){if(x == 0){return 0;}int left = 1;int right = x / 2;int mid;int ans = -1;while(left <= right){mid = left + ((right - left)>>1);if(mid <= x/mid){ans = mid;left = mid + 1;}else if(mid > x/mid){right = mid - 1;}}return ans;}

唯一要注意的一点就是,这里我们不可以用mid*mid <= x,要改成除法,用mid <= x / mid,否则这个题就会数值溢出导致出错…

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

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

相关文章

【JAVA重要知识 | 第一篇】一篇文章读懂HashMap(存储、扩容、初始化过程)

文章目录 1.一篇文章读懂HashMap&#xff08;存储、扩容、初始化过程&#xff09;1.1HashMap简介1.1.1特点1.1.2优点1.1.3缺点 1.2深入解读HashMap1.2.1常用常量和变量&#xff08;1&#xff09;常用常量&#xff08;2&#xff09;常用变量 1.2.2存储过程&#xff08;1&#xf…

诊所门诊电子处方软件操作教程及试用版下载,医务室处方笺管理系统模板教程

诊所门诊电子处方软件操作教程及试用版下载&#xff0c;医务室处方笺管理系统模板教程 一、前言 以下软件程序教程以 佳易王诊所电子处方软件V17.0为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 如上图&#xff0c;点击基本信息设置——处方配…

Python编程小案例—利用flask查询本机IP归属并输出网页图片

Python编程小案例—利用flask查询本机IP归属并输出网页图片 环境&#xff1a;Pycharm Mac OS 源码如下&#xff1a; from flask import Flask, render_template, requestapp Flask(__name__)app.route(/) def index():return render_template(IP查询.html)if __name__ __…

如何正确选择一台大路灯?2024五大出众品牌大路灯推荐,附超全科普知识整理

大路灯的使用操作非常简便&#xff0c;而且能够提供最适合目前用眼的光线环境。但如今市场中却有一些劣质大路灯&#xff0c;它们的使用体验不佳&#xff0c;很多客户反馈说可能会出现光线不稳定、刺眼等问题&#xff0c;甚至会有让用户有损伤视力的风险。那么如何选择一台大路…

华硕ROG玩家国度幻16air 2024原装系统恢复安装教程方法

华硕ROG玩家国度幻16air 2024原装系统恢复安装教程方法 重建ASUSRECOVERY恢复功能 支持型号&#xff1a; GU605MI&#xff0c;GU605MY&#xff0c;GU605MZ GU605MV&#xff0c;GU605MU 分3种安装方法 远程恢复安装&#xff1a;https://pan.baidu.com/s/166gtt2okmMmuPUL1…

Spring对IoC的实现

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…

前端monorepo大仓共享复杂业务组件最佳实践

一、背景 在 Monorepo 大仓模式中&#xff0c;我们把组件放在共享目录下&#xff0c;就能通过源码引入的方式实现组件共享。越来越多的应用愿意走进大仓&#xff0c;正是为了享受这种组件复用模式带来的开发便利。这种方式可以满足大部分代码复用的诉求&#xff0c;但对于复杂…

JAVA *数据库连接池 * 接JDBC

一.介绍: 数据库连接池实际上就是一个 " 容器 " 当有多个拥护需要访问数据库的时候, 一个用户会打开一个数据库连接, 但是!当用户离开的时候,就会断开数据库连接,那么数据库连接就作废了,之后如果还有用户需要进行访问,需要再建立一个数据库连接......循环往复, …

【Mybatis】快速入门 基本使用 第一期

文章目录 Mybatis是什么&#xff1f;一、快速入门&#xff08;基于Mybatis3方式&#xff09;二、MyBatis基本使用2.1 向SQL语句传参2.1.1 mybatis日志输出配置2.1.2 #{}形式2.1.3 ${}形式 2.2 数据输入2.2.1 Mybatis总体机制概括2.2.2 概念说明2.2.3 单个简单类型参数2.2.4 实体…

Web组态可视化编辑器 快速绘制组态

随着工业智能制造的发展&#xff0c;工业企业对设备可视化、远程运维的需求日趋强烈&#xff0c;传统的单机版组态软件已经不能满足越来越复杂的控制需求&#xff0c;那么实现Web组态可视化界面成为了主要的技术路径。 行业痛点 对于软件服务商来说&#xff0c;将单机版软件转变…

计算机视觉基础知识(十六)--图像识别

图像识别 信息时代的一门重要技术;目的是让计算机代替人类处理大量的物理信息;随着计算机技术的发展,人类对图像识别技术的认识越来越深刻;图像识别技术利用计算机对图像进行处理\分析\理解,识别不同模式的目标和对象;过程分为信息的获取\预处理\特征抽取和选择\分类器设计\分…

WebServer -- 注册登录

目录 &#x1f349;整体内容 &#x1f33c;流程图 &#x1f382;载入数据库表 提取用户名和密码 &#x1f6a9;同步线程登录注册 补充解释 代码 &#x1f618;页面跳转 补充解释 代码 &#x1f349;整体内容 概述 TinyWebServer 中&#xff0c;使用数据库连接池实现…

【深度学习笔记】计算机视觉——图像增广

图像增广 sec_alexnet提到过大型数据集是成功应用深度神经网络的先决条件。 图像增广在对训练图像进行一系列的随机变化之后&#xff0c;生成相似但不同的训练样本&#xff0c;从而扩大了训练集的规模。 此外&#xff0c;应用图像增广的原因是&#xff0c;随机改变训练样本可以…

Python + Selenium —— 下拉菜单处理!

传统的下拉菜单 Select 元素&#xff0c;由一个 Select 一系列的 option 元素构成。 <select id"source" name"source"><option value"">--请选择--</option><option value"1001">网络营销</option>&…

3.3 序列式容器-deque、stack、queue、heap、priority_queue

deque 3.1定义 std::deque&#xff08;双端队列&#xff09;是C标准模板库&#xff08;STL&#xff09;中的一种容器&#xff0c;表示双端队列数据结构。它提供了在两端高效地进行插入和删除操作的能力。与vector的连续线性空间类似&#xff0c;但有所不同&#xff0c;deque动…

基于ssm旅社客房收费管理系统+vue

目 录 目 录 I 摘 要 III ABSTRACT IV 1 绪论 1 1.1 课题背景 1 1.2 研究现状 1 1.3 研究内容 2 2 系统开发环境 3 2.1 vue技术 3 2.2 JAVA技术 3 2.3 MYSQL数据库 3 2.4 B/S结构 4 2.5 SSM框架技术 4 3 系统分析 5 3.1 可行性分析 5 3.1.1 技术可行性 5 3.1.2 操作可行性 5 3…

STM32使用FlyMcu串口下载程序与STLink Utility下载程序

文章目录 前言软件链接一、FlyMcu串口下载程序原理优化手动修改跳线帽选项字节其他功能 二、STLink Utility下载程序下载程序选项字节固件更新 前言 本文主要讲解使用FlyMcu配合USART串口为STM32下载程序、使用STLink Utility配合STLink为STM32下载程序&#xff0c;以及这两个…

代码随想录算法训练营第62/63天| 503.下一个更大元素II、42. 接雨水、84.柱状图中最大的矩形

文章目录 503.下一个更大元素II思路代码 42. 接雨水思路代码 84.柱状图中最大的矩形思路代码 503.下一个更大元素II 题目链接&#xff1a;503.下一个更大元素II 文章讲解&#xff1a;代码随想录|503.下一个更大元素II 思路 和739. 每日温度 (opens new window)也几乎如出一辙&…

C++/数据结构:AVL树

目录 一、AVL树的概念 二、AVL树的实现 2.1节点定义 2.2节点插入 三、AVL树的旋转 3.1新节点插入较高左子树的左侧&#xff1a;右单旋 3.2新节点插入较高右子树的右侧&#xff1a;左单旋 3.3新节点插入较高左子树的右侧---左右&#xff1a;先左单旋再右单旋 3.4新节点插…

SLAM基础知识-卡尔曼滤波

前言&#xff1a; 在SLAM系统中&#xff0c;后端优化部分有两大流派。一派是基于马尔科夫性假设的滤波器方法&#xff0c;认为当前时刻的状态只与上一时刻的状态有关。另一派是非线性优化方法&#xff0c;认为当前时刻状态应该结合之前所有时刻的状态一起考虑。 卡尔曼滤波是…