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

文章目录

      • 情景一 : 二分查找
      • 情景二 : 找出一个 >= 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;点击基本信息设置——处方配…

Acwing---1208. 翻硬币

翻硬币 1.题目2.基本思想3.代码实现 1.题目 小明正在玩一个“翻硬币”的游戏。 桌上放着排成一排的若干硬币。我们用 * 表示正面&#xff0c;用 o 表示反&#xff08;是小写字母&#xff0c;不是零&#xff09;。 比如&#xff0c;可能情形是&#xff1a;**oo***oooo 如果同…

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__ __…

文心一言 Python编程之

给一个包含n个整数的数组nums&#xff0c;判断nums中是否存在三个元素a,b,c&#xff0c;使得abc0?请你找出所有和为0且不重复的三元组。 注意&#xff1a;答案中不可以包含重复的三元组。 示例1&#xff1a; 输入&#xff1a;nums[-1,0,1,2,-1,-4] 输出&#xff1a;[[-1,-1,2…

中介者模式

定义&#xff1a;中介者模式&#xff08;Mediator Pattern&#xff09;又称为调节者模式或调停者模式。用一个中介对象封装一系列的对象交互&#xff0c;中介者使各对象不需要显式的相互作用&#xff0c;从而使其耦合松散&#xff0c;而且可以独立地改变它们之间的交互。 适用…

如何正确选择一台大路灯?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;️…

Qt使用QSettings类来读写ini

在Qt中&#xff0c;可以使用QSettings类来读写ini文件。QSettings提供了一个简单的接口&#xff0c;用于访问和修改ini文件中的键值对。 下面是使用QSettings类来写入ini文件的示例代码&#xff1a; #include <QCoreApplication> #include <QSettings>int main(i…

前端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;将单机版软件转变…

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

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

重拾C++之菜鸟刷算法第6篇---栈与队列

栈与队列 一、用栈实现队列 题目 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff1a; 实现 MyQueue 类&#xff1a; void push(int x) 将元素 x 推到队列的末尾int pop() 从队列的开头移除…

【Hadoop】使用Metorikku框架读取hive数据统计分析写入mysql

一、定义作业文件 作业文件 该文件将包括输入源、输出目标和要执行的配置文件的位置&#xff0c;具体内容如下 metrics:- /user/xrx/qdb.yaml # 此位置为hdfs文件系统目录 inputs: output:jdbc:connectionUrl: "jdbc:mysql://233.233.233.233:3306/sjjc"user: &quo…

虚拟帆船:利用技术出海的探险家

在数字化的浪潮中&#xff0c;一个新时代的探险家诞生了。他们不是在寻找未知大陆的勇士&#xff0c;而是在寻求跨界电商和全球游戏市场的先锋。这些现代探险家的帆船是由SOCKS5代理和代理IP构成的&#xff0c;他们的海图则是由数据和市场分析绘制的。 出海的第一步&#xff1a…

WebServer -- 注册登录

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

Linux 内核irq_stack遍历

环境Centos 4.18.0-80.el8.x86_64 一、x86架构堆栈类型说明 https://www.kernel.org/doc/Documentation/x86/kernel-stacks int get_stack_info(unsigned long *stack, struct task_struct *task,struct stack_info *info, unsigned long *visit_mask) {if (!stack)goto unk…