LeetCode-刷题记录-二分法合集(本篇blog会持续更新哦~)

一、二分查找概述

二分查找(Binary Search)是一种高效的查找算法,适用于有序数组或列表。(但其实只要满足二段性,就可以使用二分法,本篇博客后面博主会持续更新一些题,来破除一下人们对“只有有序才能二分”的误解。)

在这里插入图片描述

二分通过反复将查找范围分为两半,并根据目标值与中间元素的大小关系来确定下一步查找的方向,从而快速定位目标值的位置。

二、二分法代码实现

三、二分法习题合集

1.LeetCode 35 搜索插入位置

在这里插入图片描述
在这里插入图片描述

  • 解法

在这里插入图片描述

public static int searchInsert(int[] nums, int target) {int left = 0, right = nums.length - 1;// 使用循环来查找目标值或确定插入位置while (left <= right) {int mid = left + (right - left) / 2; // 计算中间位置,避免整数溢出问题if (nums[mid] > target) {right = mid - 1; // 如果中间值大于目标值,缩小搜索范围至左半部分} else if (nums[mid] < target) {left = mid + 1; // 如果中间值小于目标值,缩小搜索范围至右半部分} else {return mid; // 找到目标值,直接返回索引}}// 循环结束时,left 指向应该插入的位置return left;
}
  • 这里博主解释一下为什么最后返回left(debug走一下流程或者在草稿纸上画一画其实就很容易看出来啦~)。

函数 searchInsert 的目标是在给定的有序数组 nums 中查找目标值 target 的插入位置(如果目标值不存在于数组中)。

如果数组中存在目标值,则返回目标值的索引;如果不存在,则返回应该插入的位置索引,使得插入后数组依然保持有序。

插入位置保持有序性

  • 返回 left 而不是 right 是因为当循环结束时,left 恰好指向比 target 大的第一个元素的位置,或者数组的末尾位置(如果 target 大于数组中的所有元素),这正是目标值应该插入的位置,可以保持数组的有序性。

2.LeetCode 69 x的平方

在这里插入图片描述

  • 解法

在这里插入图片描述

public static int mySqrt(int x) {if (x == 0 || x == 1) return x;int left = 0, right = x;int ans = 0;while (left <= right) {int mid = left + (right - left) / 2;//防止越界~因为 mid*mid 数值过大 int可能会越界 或者 强转一下也可——(long)mid*midif (mid < x / mid) { //如果这个整数的平方 严格小于 输入整数,那么这个整数 可能 是我们要找的那个数(重点理解这句话)。ans = mid;//所以我们更新答案left = mid + 1;} else if (mid > x / mid) { //如果这个整数的平方 严格大于 输入整数,那么这个整数  肯定不是  我们要找的那个数;right = mid - 1;} else { //如果这个整数的平方 恰好等于 输入整数,那么我们就找到了这个整数;return mid;}}return ans;}

3.LeetCode 367 有效的完全平方数

在这里插入图片描述

  • 解法

在这里插入图片描述

public static boolean isPerfectSquare(int num) {int left = 0, right = num;// 使用二分查找来确定是否为完全平方数while (left <= right) {int mid = left + (right - left) / 2; // 计算中间值,避免整数溢出问题if ((long) mid * mid < num) {left = mid + 1; // 如果 mid 的平方小于 num,说明目标值在右半部分,缩小搜索范围至右半部分} else if ((long) mid * mid > num) {right = mid - 1; // 如果 mid 的平方大于 num,说明目标值在左半部分,缩小搜索范围至左半部分} else {return true; // 如果 mid 的平方等于 num,直接返回 true,表示找到完全平方数}}// 循环结束时,未找到完全平方数,返回 falsereturn false;
}

4.LeetCode 34 在排序数组查找元素的第一个和最后一个位置

在这里插入图片描述

  • 解法

本题拆分成两个函数,分别处理较好,不过这个对处理二分的熟练度要求还挺高,比如说left<=right 还是left<right以及左右指针什么时候该怎么移动都有讲究,一个小细节不对的话就得不到正确的答案。

大概的二分的模版大家都知道,区别就在于具体问题的边界问题,是需要自己思考的。

建议有电脑的小伙伴可以debug走一下流程 ,可以看出来左右指针怎么移动的,慢慢调试;或者在纸上画一画,看一看自己写的二分是怎么个流程~


在这里插入图片描述

public static int[] searchRange(int[] nums, int target) {int[] ans = {-1, -1};// 特殊情况处理:数组为空,或者目标值不在数组范围内if (nums.length == 0 || nums[0] > target || nums[nums.length - 1] < target) return ans;// 查找第一次出现的位置int first = findFirst(nums, target);if (first == -1) return ans; // 如果找不到目标值,返回初始的{-1, -1}ans[0] = first;// 查找最后一次出现的位置ans[1] = findLast(nums, target);return ans;
}// 找到元素第一次出现的位置
public static int findFirst(int[] nums, int target) {int left = 0, 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; // 目标值在左半部分或者当前位置就是目标值}}// 当退出循环时,left 指向第一个大于等于目标值的位置return nums[left] == target ? left : -1; // 如果找到目标值,返回该位置;否则返回 -1
}// 找到元素最后一次出现的位置
public static int findLast(int[] nums, int target) {int left = 0, 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; // 目标值在左半部分}}// 当退出循环时,right 指向最后一个小于等于目标值的位置return right; // 直接返回 right,即最后一次出现的位置
}

5.LeetCode 33 搜索旋转排序数组

在这里插入图片描述

  • 解法

题目要求我们设计一个时间复杂度为O(logN)的算法,很容易就想到二分法。

但是本题整个数组并不是完全有序的,而是被“旋转”拆分成了两个部分。

如果我们能找到那个旋转点的话,在两个有序的部分进行二分查找就非常轻松了。

那么如果直接遍历数组去找旋转点的话,时间复杂度还是会上升到O(N),不符合题目要求。

我们能不能也用二分去寻找这个旋转点呢? 答案是可以的。

eg 4 5 6 7 1 2 3——旋转点在 1 处
我们以arr[0],也就是4为基准,用mid 去跟 arr[0]比较,如果mid>arr[0],说明旋转点在mid右边,如果mid<arr[0],那么可能当前就是旋转点,或者旋转点在右边。

这也算是满足二段性的一个例子了——二分法并不是一定要有序的时候才能用,满足二段性时,也可以使用。


//查找旋转点 
public static int findRotationPointIndex(int[] arr) {// 如果数组长度为2,直接返回较小元素的索引if (arr.length == 2) return arr[0] < arr[1] ? 0 : 1;// 初始化左右边界int left = 0;int right = arr.length - 1;// 二分查找旋转点while (left < right) {int mid = left + (right - left) / 2;if (arr[mid] >= arr[0]) {left = mid + 1;  // mid处于前半段递增序列,旋转点在右半段} else {right = mid;     // mid处于后半段递增序列或是旋转点}}return left;  // left指向旋转点的索引
}

查找到旋转点之后,我们再在两端进行二分查找就比较容易了。

public int search(int[] arr, int target) {// 如果数组长度为1,直接比较目标值与数组唯一元素if (arr.length == 1) return target == arr[0] ? 0 : -1;// 找到旋转点的索引int index = findRotationPointIndex(arr);// 初始化左右边界int left = 0;int right = arr.length - 1;// 确定二分查找的范围if (index == 0) {// 数组没有旋转,直接在整个数组上执行二分查找return binaryFind(arr, left, right, target);}if (target >= arr[0]) {right = index; // 目标值可能在旋转点之前(包括旋转点)} else {left = index; // 目标值在旋转点之后}// 在确定的范围内执行二分查找return binaryFind(arr, left, right, target);}//二分查找public static int binaryFind(int[] arr, int left, int right, int target) {while (left <= right) {int mid = left + (right - left) / 2;if (arr[mid] == target) {return mid;} else if (arr[mid] < target) {left = mid + 1;} else {right = mid - 1;}}return -1;}

在这里插入图片描述


6.LeetCode 475 供暖器

在这里插入图片描述

  • 解法

核心思路就是两句话:
(1)对于每个房屋,要么用前面的暖气,要么用后面的,二者取近的,得到距离;
(2)对于所有的房屋,选择最大的上述距离。

所以我们可以将heaters排好序,然后对每个房屋利用二分法去搜索最近的(相邻的)供暖器即可。

代码实现:

public int findRadius(int[] houses, int[] heaters) {// 首先对加热器的位置数组进行排序Arrays.sort(heaters);// 初始化答案为0int ans = 0;int n = houses.length;// 遍历房屋的位置数组for (int i = 0; i < n; i++) {// 对于每个房屋位置,调用二分查找函数找到其最近的加热器,并更新答案ans = Math.max(binarySearch(heaters, houses[i]), ans);}// 返回最大半径return ans;}// 二分查找函数,用于找到距离目标最近的加热器public int binarySearch(int[] nums, int target) {int n = nums.length;// 如果目标大于等于加热器数组中最后一个加热器的位置,直接返回目标与最后一个加热器位置的距离差if (target >= nums[n - 1]) return target - nums[n - 1];// 如果目标小于等于加热器数组中第一个加热器的位置,直接返回第一个加热器位置与目标的距离差if (target <= nums[0]) return nums[0] - target;// 初始化左右边界int l = 0, r = n - 1;// 开始二分查找while (l <= r) {int mid = l + (r - l) / 2;if (nums[mid] == target) {return 0; // 如果找到目标位置,返回距离差为0} else if (nums[mid] < target) {l = mid + 1; // 如果目标在当前中间值的右侧,更新左边界} else {r = mid - 1; // 如果目标在当前中间值的左侧,更新右边界}}// 循环结束时,l指向的位置即为最终找到的最近的那个比他大的加热器的位置//取两个差值的最小值return Math.min(nums[l] - target, target - nums[l - 1]);}

7.LeetCode 287 寻找重复数

在这里插入图片描述

  • 这道题博主咋也想不出来能用二分法哈哈哈哈,想破脑壳也找不到二段性

  • 但是 还有有二段性滴~ 哈哈哈哈 刚开始看不太明白没关系 博主也琢磨了好一会儿 差点放弃了…

  • 自己在纸上找一些例子画一画 慢慢就能get到这个点啦

在这里插入图片描述

  • 代码实现
// 寻找重复元素的方法,输入是一个整数数组 nums
public int findDuplicate(int[] nums) {int n = nums.length; // 数组的长度int l = 1, r = n - 1; // 设定搜索范围,因为题目给出了1到n-1之间的数字重复,所以左边界为1,右边界为n-1int ans = -1; // 初始化答案为-1,因为题目保证了一定存在重复元素,因此初始值不影响结果// 开始二分搜索while (l <= r) {int mid = l + (r - l) / 2; // 计算中间值int cnt = 0; // 统计小于等于mid的元素个数for (int num : nums) {if (num <= mid) {cnt++;}}// 如果小于等于mid的元素个数(cnt)小于等于mid本身,则重复元素在[mid+1, r]范围内if (cnt <= mid) {l = mid + 1; // 更新左边界,缩小搜索范围到[mid+1, r]} else {r = mid - 1; // 否则重复元素在[l, mid-1]范围内ans = mid; // 更新答案为当前的mid,因为mid可能是重复的数字}}return ans; // 返回找到的重复元素
}

博主在这篇博客里面会继续更新二分查找的算法题哦~

欢迎点赞关注收藏~

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

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

相关文章

(已解决)Adobe Flash Player已不再受支持

文章目录 前言解决方案 前言 一般来说&#xff0c;很少遇到官方网站使用Adobe Flash Player来进行录用名单公示了。但是&#xff0c;今天就偏偏遇到一次&#xff0c; 用谷歌浏览器打不开&#xff0c; 点了没有反应&#xff0c;用其他的浏览器&#xff0c;例如windows自带的那…

Golang | Leetcode Golang题解之第207题课程表

题目&#xff1a; 题解&#xff1a; func canFinish(numCourses int, prerequisites [][]int) bool {var (edges make([][]int, numCourses)indeg make([]int, numCourses)result []int)for _, info : range prerequisites {edges[info[1]] append(edges[info[1]], info[0]…

数据结构:期末考 第六次测试(总复习)

一、 单选题 &#xff08;共50题&#xff0c;100分&#xff09; 1、表长为n的顺序存储的线性表&#xff0c;当在任何位置上插入或删除一个元素的概率相等时&#xff0c;插入一个元素所需移动元素的平均个数为&#xff08; D &#xff09;.&#xff08;2.0&#xff09; A、 &am…

在node环境使用MySQL

什么是Sequelize? Sequelize是一个基于Promise的NodeJS ORM模块 什么是ORM? ORM(Object-Relational-Mapping)是对象关系映射 对象关系映射可以把JS中的类和对象&#xff0c;和数据库中的表和数据进行关系映射。映射之后我们就可以直接通过类和对象来操作数据表和数据了, 就…

join()方法——连接字符串、元组、列表和字典

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法参考 join()方法用于连接字符串数组。将字符串、元组、列表中的元素以指定的字符&#xff08;分隔符&#xff09;连接生成一个新的字符串&#…

喜报 | 极限科技获得北京市“创新型”中小企业资格认证

2024年6月20日&#xff0c;北京市经济和信息化局正式发布《关于对2024年度4月份北京市创新型中小企业名单进行公告的通知》&#xff0c;极限数据&#xff08;北京&#xff09;科技有限公司凭借其出色的创新能力和卓越的企业实力&#xff0c;成功获得“北京市创新型中小企业”的…

学会python——在excel中写入数据(python实例十三)

目录 1.认识Python 2.环境与工具 2.1 python环境 2.2 Visual Studio Code编译 3 .想Excel中写入数据 3.1 代码构思 3.2 代码实例 3.3 运行结果 4.总结 1.认识Python Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的…

数据结构算法之B树

一、绪论 1.1 数据结构的概念和作用 1.2 B树的起源和应用领域 二、B树的基本原理 2.1 B树的定义和特点 2.2 B树的结构和节点组成 2.3 B树的插入 2.4 B树的删除操作 三、B树的优势和应用 3.1 B树在数据库系统中的应用 3.2 B树在文件系统中的应用 3.3 B树在内存管理中…

isupper()方法——判断字符串是否全由大写字母组成

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法参考 isupper()方法用于判断字符串中所有的字母是否都是大写。isupper()方法的语法格式如下&#xff1a; str.isupper() 如果字符串中包含至少…

实验三 时序逻辑电路实验

仿真 链接&#xff1a;https://pan.baidu.com/s/1z9KFQANyNF5PvUPPYFQ9Ow 提取码&#xff1a;e3md 一、实验目的 1、通过实验&#xff0c;理解触发的概念&#xff0c;理解JK、D等常见触发器的功能&#xff1b; 2、通过实验&#xff0c;加深集成计数器功能的理解&#xff0c;掌…

⭐Ollama的本地安装⚡

先来逛一下咱们的主角Ollama的官网地址&#xff1a; Ollama 大概长这个样子&#x1f914; 因为本地系统的原因&#xff0c;文章只提供Widows的安装方式&#xff0c;使用Linux和Mac的大佬&#xff0c;可以自行摸索&#x1f9d0; 下载完成后就是安装了&#x1f355;&#xff0c…

一、Redis简介

一、Redis介绍与一般应用 1.1 基本了解 Redis全称Remote Dictionary Server(远程字典服务)&#xff0c; 是一个开源的高性能键值存储系统&#xff0c;通常用作数据库、缓存和消息代理。使用ANSI C语言编写遵守BSD协议&#xff0c;是一个高性能的Key-Value数据库提供了丰富的数…

苹果笔记本能玩网页游戏吗 苹果电脑玩steam游戏怎么样 苹果手机可以玩游戏吗 mac电脑安装windows

苹果笔记本有着优雅的机身、强大的性能&#xff0c;每次更新迭代都备受用户青睐。但是&#xff0c;当需要使用苹果笔记本进行游戏时&#xff0c;很多人会有疑问&#xff1a;苹果笔记本能玩网页游戏吗&#xff1f;苹果笔记本适合打游戏吗&#xff1f;本文将讨论这两个话题&#…

6-14题连接 - 高频 SQL 50 题基础版

目录 1. 相关知识点2. 例子2.6. 使用唯一标识码替换员工ID2.7- 产品销售分析 I2.8 - 进店却未进行过交易的顾客2.9 - 上升的温度2.10 - 每台机器的进程平均运行时间2.11- 员工奖金2.12-学生们参加各科测试的次数2.13-至少有5名直接下属的经理2.14 - 确认率 1. 相关知识点 left …

树状数组——点修区查与区修点查

树状数组是一种代码量小&#xff0c;维护区间的数据结构 他可以实现&#xff1a; 1.区间修改&#xff0c;单点查询 2.单点修改&#xff0c;区间查询 当然&#xff0c;二者不可兼得&#xff0c;大人全都要的话&#xff0c;请选择线段树 前置知识&#xff1a; lowbit(x)操作…

LDM论文解读

论文名称&#xff1a;High-Resolution Image Synthesis with Latent Diffusion Models 发表时间&#xff1a;CVPR2022 作者及组织&#xff1a;Robin Rombach, Andreas Blattmann, Dominik Lorenz,Patrick Esser和 Bjorn Ommer, 来自Ludwig Maximilian University of Munich &a…

独一无二的设计模式——单例模式(Java实现)

1. 引言 亲爱的读者们&#xff0c;欢迎来到我们的设计模式专题&#xff0c;今天的讲解的设计模式&#xff0c;还是单例模式哦&#xff01;上次讲解的单例模式是基于Python实现&#xff08;独一无二的设计模式——单例模式&#xff08;python实现&#xff09;&#xff09;的&am…

web全屏api,实现元素放大全屏,requestFullscreen,exitFullscreen

全屏api 主要方法 document.exitFullscreen(); 退出页面全屏状态&#xff0c;document是全局文档对象 dom.requestFullscreen(); 使dom进入全屏状态&#xff0c;异步&#xff0c;dom是一个dom元素 dom.onfullscreenchange&#xff08;&#xff09;; 全…

专题四:Spring源码初始化环境与BeanFactory

上文我们通过new ClassPathXmlApplicationContext("applicationContext.xml");这段代码看了下Spring是如何将Xml里面内容注入到Java对象中&#xff0c;并通过context.getBean("jmUser");方式获得了一个对象实例&#xff0c;而避开使用new 来耦合。今天我们…

【TB作品】智能台灯控制器,ATMEGA128单片机,Proteus仿真

题目 8 &#xff1a;智能台灯控制器 基于单片机设计智能台灯控制器&#xff0c;要求可以调节 LED 灯的亮度&#xff0c;实现定时开启与关闭&#xff0c; 根据光照自动开启与关闭功能。 具体要求如下&#xff1a; &#xff08;1&#xff09;通过 PWM 功能调节 LED 灯亮度&#x…