算法日记---二分查找

目录

前言

一、二分查找

1.思想

2.简单二分

3.优点

4.局限性

二、模板

1.基本模板

2.简单例题(LeetCode)

4.有重复元素的二分

5.0-1问题

总结


前言

本文通过讲解简单的二分查找配合leetcode例题对二分查找本质、模板进行了基础的总结


提示:以下是本篇文章正文内容,下面案例可供参考

一、二分查找

1.思想

二分查找本质是折半查找思想,每一轮查找的范围是上一轮的一半,每次查找比较中间元素的值和目标值的大小。比较结论决定去哪一边作为下一轮的查找范围,循环直到查找范围为空。

2.简单二分

简单二分指的是数组不包含重复的元素,重点关注每次判边的逻辑。

3.优点

速度快 O(logn)且不需要额外的空间

4.局限性

  • 有序:需要保证每次折半都有意义
  • 数组:数组寻址的复杂度是 O (1)。如果是用链表存储一串数,二分查找是无意义的。链表的寻址是 O (n)。

二、模板

1.基本模板

二分查找的模板很多样,开闭的条件不同,判断的条件也不同

最本质的问题是当前判断结束后,下一次要取左半边还是右半边缩小区间的条件是什么?判断的条件是什么 

注意:

  1. left<=right:实际进入循环时,left和right只向的元素不会进行if条件判断。比如left=right时,加此等号,才会对二者所指元素进行判断。否则不会。
  2. mid =(left+right)>>>1:因为java会把最高位看成符号位,如果两个数过大,可能会导致数据溢出问题。我们需要通过无符号右移运算符来避免这种问题。还有一种写法是mid=left+(right-left)/2
  3. 更新left和right,避免死循环
public static int binarySerach(int[] a,int target){int left=0;int right=a.length-1;while(left<=right){int mid=(left+right)>>>1;if(target<a[mid]){//目标数在左边right=mid-1;}else if(a[mid]<target){//目标书在右边left=mid+1;}else{return mid;}}return -1;
}

2.简单例题(LeetCode)

1.704. 二分查找(基本简单)

class Solution {public int search(int[] nums, int target) {int left=0;int right=nums.length-1;while(left<=right){int mid=(left+right)>>>1;if(nums[mid]<target){left=mid+1;}else if(nums[mid]>target){right=mid-1;}else{return mid;}}return -1;}
}

2.744.寻找比目标字母大的最小字母

class Solution {public char nextGreatestLetter(char[] letters, char target) {int left=0;int right=letters.length-1;while(left<=right){int mid=(left+right)>>>1;if(letters[mid]<=target){left=mid+1;}else{right=mid-1;}}return left<letters.length?letters[left]:letters[0];}
}

3.74. 搜索二维矩阵

class Solution {public boolean searchMatrix(int[][] matrix, int target) {int left=0;//使用m*n将二维转为一维int m=matrix[0].length;int n=matrix.length;int right=m*n-1;while(left<=right){int mid=(left+right)>>>1;int x=matrix[mid/m][mid%m];//把mid元素转换回原二维矩阵的位置if(x==target){return true;}else if(x>target){right=mid-1;}else{left=mid+1;}}return false;}
}

4.162. 寻找峰值

此题究其本质依然是二分查找,我们需要根据题目重要条件进行理解

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

以下做法需要注意边界情况的判断

class Solution {public int findPeakElement(int[] nums) {int n = nums.length;if (n == 1) {return 0;}int left = 0, right = n - 1;while (left <= right) {int mid = left + (right - left) / 2;// 边界情况判断:数组第一个元素是峰值(只有它自己,或者比下一个大)if (mid == 0) {if (nums[mid] > nums[mid + 1]) {return mid;}}// 边界情况判断:数组最后一个元素是峰值(只有它自己,或者比前一个大)else if (mid == n - 1) {if (nums[mid] > nums[mid - 1]) {return mid;}}// 中间位置是峰值(比左右都大)else if (nums[mid] > nums[mid - 1] && nums[mid] > nums[mid + 1]) {return mid;}// 判断峰值在左侧还是右侧if (nums[mid] < nums[mid + 1]) {// 右侧有上升趋势,峰值在右侧left = mid + 1;} else if (nums[mid] < nums[mid - 1]) {// 左侧有上升趋势,峰值在左侧right = mid - 1;}}// 理论上不会走到这里,因为题目保证有解return -1;
}}

题解中的做法是无需单独判断边界情况的,也没有主动对mid元素与左右两元素进行比较

因为左右边界都是负无穷,找到往递增的一边方向找就一定能找到峰值(图中白圈内区域)。这就代表着 只要数组中存在一个元素比相邻元素大,那么沿着它一定可以找到一个峰值。

特点:一分为二后,一侧是有序数组,另一侧是循环数组。

根据这个特点,先判断有序数组、循环数组分别在哪一侧,再判断 target 在有序数组 还是 循环数组中

判断方法是让 target 和有序数组的首尾做比较,看是否在有序数组中。

1. 3. 搜索旋转排序数组

class Solution {public int search(int[] nums, int target) {int left=0;int right=nums.length-1;while(left<=right){int mid=(left+right)>>>1;if(nums[mid]==target){return mid;}//左半部分有序if(nums[left]<=nums[mid]){//目标值在左半部分区间内if(nums[left]<=target && target<nums[mid]){right=mid-1;}else{left=mid+1;//缩小范围到右半部分区间}}// 右半部分是有序的else {// 目标值在右半部分有序区间内if (nums[mid] < target && target <= nums[right]) {left = mid + 1;} else {right = mid - 1;//缩小范围到左半部分区间}}}return -1;}}

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

不多说了,都在注解里:

最主要的还是需要判断目标值到底是在mid的左边还是右边,才能进行下一步二分。而判断依据就是根据两端递增区间的特性将nums[mid]和nums[right]进行比较。这也就是开篇说的判断取左半段还是右半段最重要的条件。

class Solution {public int findMin(int[] nums) {int left=0;int right=nums.length-1;while(left<=right){int mid=(left+right)>>>1;//首先由题可知,数组一定被分为了左右两个递增区间(或者没分,也就是0次旋转),且第一段所有元素大于第二段所有元素//需要比较nums[mid]和nums[right]的关系。//如果<=,意味着nums[mid]一定处于第二个递增区间,最小值要么是该元素,要么就在该元素左侧//如果>,意味着nums[mid]处于第一个递增区间。最小值一定在该元素右侧if(nums[mid]>nums[right]){//mid处于左半段left=mid+1;}else{//mid处于右半段if(mid==0||nums[mid]<=nums[mid-1]){//mid就是最小值,注意mid=0时索引越界问题return nums[mid];}else{//mid处于右半段,但最小值在mid的左边right=mid-1;}}}return -1;}
}

4.有重复元素的二分

通常要求找出第一个目标元素或是最后一个目标元素

存在重复元素的二分查找,无非就是多加了一个判断,判断是否为第一个/最后一个。

以查询第一个目标元素为例,判断条件就是看mid-1是否等于target,如果不是,那么mid就是我要

找的数了。这依然是二分关键。

public class BinarySearch {public static int binarySearch(int[] nums, int target) {int left = 0;int right = nums.length - 1;while (left <= right) {int mid = left + (right - left) / 2;if (nums[mid] < target) {left = mid + 1;} else if (nums[mid] > target) {right = mid - 1;} else {// 当找到目标值时,判断是否是第一个出现的位置if (mid == 0 || nums[mid - 1] != target) {//是第一个元素,注意索引越界问题。return mid;} else {right = mid - 1;}
//以下为找最后一个目标元素的判断条件
//if (mid == nums.length-1 || nums[mid+1]!=target){
//}else{
// left=mid+1;}}}return -1;}public static void main(String[] args) {int[] nums = {1, 3, 8, 8, 8, 9};int target = 8;int result = binarySearch(nums, target);System.out.println("第一个目标值 " + target + " 的索引是: " + result);}
}

5.0-1问题

点到为止,下期再见。


总结

本文对二分查找进行简单讲解,还有比较常见的二分查找应用“0-1问题”留着下期讲解。

二分的模板多种多样,但究其本质最重要的还是如何判断下一次二分的区间,取左边还是取右边。这个就是需要根据不同题目思考的点了

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

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

相关文章

Level Set(水平集)算法——形象化讲解

目录 维度一&#xff1a;核心思想与比喻&#xff08;它像什么&#xff1f;&#xff09; 维度二&#xff1a;要解决什么问题&#xff1f;&#xff08;它能干嘛&#xff1f;有什么用&#xff1f;&#xff09; 维度三&#xff1a;工作原理&#xff08;它是怎么做到的&#xff1…

DDoS 攻防“军备竞赛”的幕后

谈到 DDoS&#xff08;分布式拒绝服务攻击&#xff09;&#xff0c;很多人会想到“黑客租用肉鸡发流量&#xff0c;网站直接崩”。但事实上&#xff0c;如今的 DDoS 攻防早已变成一场 军备竞赛。攻击者的武器越来越“工业化”&#xff1a;僵尸网络商品化&#xff1a;黑市上&…

如何用 Rust 重写 SQLite 数据库(二):是否有市场空间?

用 Rust 实现一个类似 SQLite 的嵌入式数据库非常有意义&#xff0c;但需要结合具体目标和场景来评估其价值。以下从技术、生态、市场需求和个人成长等多个维度展开分析&#xff0c;并给出结论。一、技术价值&#xff1a;Rust 与数据库的天然契合 SQLite 作为全球装机量最大的数…

【Web】ImaginaryCTF 2025 wp

目录 imaginary-notes certificate codenames-1 passwordless pearl imaginary-notes I made a new note taking app using Supabase! Its so secure, I put my flag as the password to the "admin" account. I even put my anonymous key somewhere in the si…

oracel如何找到外键子表

要找到导致外键约束冲突的子表&#xff08;即包含"child record"的表&#xff09;&#xff0c;可以通过以下SQL查询在Oracle数据库中定位&#xff1a;1. 查询约束基本信息&#xff08;确定父表和子表&#xff09;SELECT owner, constraint_name, table_name AS child…

智源研究院新研究:突破物理世界智能边界的RoboBrain 2.0,将重构具身AI能力天花板

当你对着家用机器人说"把杯子放在笔筒和键盘之间&#xff0c;对齐杯身logo"时&#xff0c;它能精准理解空间关系并执行动作&#xff1b;当多台机器人在超市协作补货时&#xff0c;它们能自主规划轨迹、避免冲突并完成长周期任务——这些曾经出现在科幻电影中的场景&a…

【2025】Office核心组件Microsoft word,Excel,PowerPoint详细使用指南

Office 核心组件使用指南 Microsoft Word 文字处理 Word主要用于创建和编辑文档&#xff0c;如信件、报告、论文等。 2025Office&#x1f517; 1. 界面认识 快速访问工具栏&#xff1a;位于左上角&#xff0c;可自定义保存、撤销、恢复等常用命令。功能区&#xff1a;顶部…

【模型训练篇】VeRL的使用 - RL(PPO)与源码

继续学习字节家的VeRL&#xff0c;今天来看看VeRL的RL&#xff0c;是VeRL系列的第三篇文章&#xff08;话说近期好多大事儿&#xff0c;我司发布了Longcat、韩立结婴、阿里周五发布了QWen-Next都是好东西啊&#xff0c;学不过来了damn&#xff09; 底层分布式能力基础Ray&…

QML Charts组件之折线图的鼠标交互

目录前言相关系列代码示例详解&#xff08;LineSeriesDemo3.qml&#xff09;功能概览运行效果代码说明工程下载参考前言 接上文&#xff08;QML Charts组件之折线图的基础属性&#xff09;&#xff0c;本文将重点介绍LineSeries的鼠标交互&#xff0c;包括&#xff1a;鼠标拖拽…

二值信号量——学习笔记12

本文是笔者在学习 正点原子官方 的《【正点原子】手把手教你学FreeRTOS实时系统》系列视频时整理的笔记。 视频讲解清晰透彻&#xff0c;非常感谢UP主的无私奉献&#xff01;原课程链接如下&#xff1a; &#x1f449; B站视频链接&#xff1a;​​​​​​【正点原子】手把手教…

裸机开发 时钟配置,EPIT

1.概念时钟(clock)&#xff1a;在电子系统中是一个产生稳定、周期性振荡信号的电路或组件。这个信号像节拍器或心跳一样&#xff0c;为数字电路中的各种操作提供同步时序基准。PLL&#xff08;phase locked loop&#xff09;锁相环电路: 倍频PFD&#xff08;phase fractional P…

Linux-文本三剑客(grep、sed、awk)

Linux-文本三剑客前言一、grep二、sed三、awk模式 -- 正则表达式关系表达式、运算符表达模式匹配表达式动作 输出流程控制参数传递&#xff0c;awk接受外部变量统计数组的使用分组统计练习常用内置函数前言 grep、sed、awk 被称为 “文本三剑客”&#xff0c;它们是处理文本文…

主流反爬虫、反作弊防护与风控对抗手段

文章目录1. 写在前面2. 指纹检测3. 行为验证3. 加固防护4. 链路检测5. 风控埋点6. 游客注册7. 数据防护8. 账号权重9. 反调阻断【&#x1f3e0;作者主页】&#xff1a;吴秋霖 【&#x1f4bc;作者介绍】&#xff1a;擅长爬虫与JS加密逆向分析&#xff01;Python领域优质创作者、…

金蝶云星空插件开发记录(一)

实现目的&#xff1a;新增供应商保存后&#xff0c;触发钉钉审批流程&#xff0c;并根据钉钉审批结果回写是否合格供应商。实现思路&#xff1a;通过BOS平台供在应商管理界面新增两个复选框字段&#xff1a;是否钉钉审批、是否合格供应商&#xff0c;若在新建供应商档案时勾选是…

企业跨区域组网新解:SD-WAN技术打造安全稳定网络体系

前言在数字化浪潮席卷全球的今天&#xff0c;企业跨区域网络互联已成为支撑业务发展的关键基础设施。传统MPLS专线虽性能稳定&#xff0c;但高昂成本和漫长部署周期令众多企业望而却步。SD-WAN技术的出现&#xff0c;正以其智能、灵活和成本效益的优势&#xff0c;重塑企业组网…

Docker 容器化

引言在解释docker是什么之前&#xff0c;我们首先应该先了解的是容器化的概念。什么是容器&#xff1f;就是一个沙箱&#xff0c;在这个沙箱中涵盖了特定应用运行的一切依赖的内容。但他不是一个操作系统&#xff0c;且和底层的操作系统是隔离的。什么是容器化&#xff1f;容器…

LeetCode刷题——hot 100(3)

题目1&#xff1a;矩阵置零题目&#xff1a;问题分析&#xff1a;使用两个布尔数组来分别记录哪行哪列出现了0&#xff0c;当出现0的行和列&#xff0c;对应的布尔数组值置为true。再次遍历数组&#xff0c;当出现行数组和列数组中的值为true&#xff0c;则对应的原数组的值置为…

Ajax-day2(图书管理)-渲染列表

本篇笔记素材来自“黑马程序员” 渲染列表图书管理一、获取数据二、渲染数据完整代码图书管理 Bootstrap 框架渲染列表&#xff08;查&#xff09;新增图书&#xff08;增&#xff09;删除图书&#xff08;删&#xff09;编辑图书&#xff08;改&#xff09; 自己的图书数据&a…

MOS管的电路

MOS管的三极都会存在以下三个电容&#xff0c;分别是&#xff1a;Cgs,Cgd,Cds 输入电容CissCgsCgd 输出电容CossCgdCds 反向传输电容CrssCgd&#xff0c;也叫米勒电容 然而&#xff0c;这三个等效电容是构成串并联组合关系&#xff0c;他们并不是独立的&#xff0c;而是相互…

STM32_05_时钟树

时钟 d用来输入数据&#xff0c;CLK就是我们的时钟&#xff0c;CPU1s中72000000HZ个时钟周期STM32的时钟树锁相环HSE时钟源HSI时钟源LSE时钟源LSI时钟源SystemInit函数SetSysClock函数SetSysClockTo72函数SystemInit()后时钟频率大小总结RCC标准库函数定义变量a&…