【LeetCode 算法专题突破】---二分查找(⭐⭐⭐)
前言
我在算法题目的海洋中畅游已久,也曾在算法竞赛中荣获佳绩。然而,我发现自己对于算法的学习,还缺乏一个系统性的总结和归类。尽管我已经涉猎过不少算法类型,但心中仍旧觉得有所欠缺,未能形成完整的算法体系。
因此,我决定踏上这次算法之旅,对常见的算法进行一次全面的梳理与归类。我希望通过这个过程,能够更深入地理解每个经典算法类型的核心知识,加强我的算法能力,并完善自己的算法体系。
同时,我也希望能够将这次学习的成果与你分享,希望对你也有所帮助。让我们一同在算法的世界里探索、成长,共同迎接未来的挑战吧!
1.经典的不能在经典的二分查找(难度⭐)
Leetcode链接:704. 二分查找
1.1题目描述:
这是一道非常典型的二分查找算法题目,可以说所有要学习二分查找算法的人都必须掌握这道题。题目要求很简单,就是在一个有序数组中查找目标值target。这道题是二分查找算法的入门题和模版题,没有掌握这道题就无法开始学习更复杂的二分查找算法题目。所以这道题对于二分查找算法的理解和掌握非常关键和必要。
1.2代码:
class Solution {
public:int search(vector<int>& nums, int target) {int left = 0, right = nums.size() - 1;int mid;while(left <= right){mid = (left + right)/2;if(nums[mid]>target){right = mid - 1;}else if(nums[mid]<target){left = mid + 1;}else{return mid;}}return -1;}
};
通过这道二分查找的典型题,我对二分查找算法的理解更进一步:
我对二分查找的区间划分有了更深的理解:
- 当mid位置的值小于target时,证明左区间[left, mid-1]都不可能存在target,所以左区间变为[mid+1, right]。
- 当mid位置的值大于target时,证明右区间[mid+1, right]都不可能存在target,所以右区间变为[left, mid-1]。
- 当mid位置的值等于target时,就找到了目标值。
我理解到二分查找的本质就是通过比较中间mid值与target的值,可以排除一半的搜索区间,使搜索范围越来越小,直到找到target。
通过这道题我对二分查找算法模板有了更加熟练的掌握,可以应用到其他二分查找题目中去。
2.在排序数组中查找元素的第一个和最后一个位置(难度⭐⭐)
Leetcode链接:34. 在排序数组中查找元素的第一个和最后一个位置
2.1题目描述:
2.2代码:
class Solution {
public:vector<int> searchRange(vector<int>& nums, int target) {int left = 0, right = nums.size() - 1, begin = -1, end = -1, mid;//找到区间左边界while(left<=right){mid = (left + right)/2;if(nums[mid] > target){right = mid - 1;}else if(nums[mid] < target){left = mid + 1;}else{begin = mid;right--;//right区间左移,使得mid左移,直到到达左区间边界,此时right正好和left重合}}left = 0, right = nums.size() - 1;//找到区间有边界while(left<=right){mid = (left + right)/2;if(nums[mid] > target){right = mid - 1;}else if(nums[mid] < target){left = mid + 1;}else{end = mid;left++;//left区间右移,使得mid右移,直到到达又区间边界,此时left正好和right重合}}return {begin,end};}
};
这道题的大思路和上面的题并没有太大区别,只是为了找到左右区间,需要两次二分查找
具体来说,在求左右区间边界时,处理mid==target的情况需要进行特别考虑:
- 求左区间边界时,需要在记录begin索引后,继续将right索引左移,使得mid向左逼近,直到不等于target时才能锁定左区间边界。
- 求右区间边界时,需要在记录end索引后,继续将left索引右移,使得mid向右逼近,直到不等于target时才能锁定右区间边界。
这种细微的逻辑调整体现了二分查找的灵活性,在保持模板框架不变的情况下,通过简单逻辑修改就可应对新的问题。
3. 有效的完全平方数(难度⭐)
Leetcode链接:367. 有效的完全平方数
3.1题目描述:
撇开具体问题不讨论,假设需要找到完全平方数,你可能会采用这样的方法:将原数进行二分,然后将得到的中间值平方,观察是否等于目标值。如果相等,那么找到了完全平方数;如果不等,就可以根据大小关系缩小搜索范围,继续二分。为什么选择这种方式呢?因为这种方法的效率相对较高。既然如此,我们为何不考虑运用二分法来解决这类问题呢?
3.2代码:
class Solution {
public:bool isPerfectSquare(int num) {long long left = 0, right = num, mid = 0;long long s;while(left<=right){mid = (left + right)/2;s = mid * mid;if(s>num){right=mid-1;}else if(s<num){left=mid+1;}else{return true;}}return false;}
};
在这个解决方案中,我们并没有深入探讨具体的代码细节,只是简单地将二分算法应用于这个场景。然而,通过这个简单的经验,我们可以得出一个更加广泛的启示:如果今后遇到类似的问题,我们可以考虑运用二分法。
4.寻找峰值(难度⭐⭐)
二分熟练度up up up~
Leetcode链接:162. 寻找峰值
4.1题目描述:
在面对这个问题时,我们甚至没有提供目标值(target),而且输入序列并不保证是有序的。这是否意味着我们可以应用二分查找算法呢?
让我们尝试通过代码来展示这一思路,看看是否能够在这样的条件下成功运用二分查找的思想解决问题。
4.2代码:
class Solution {
public:int findPeakElement(vector<int>& nums) {int left = 0, right = nums.size() - 1, mid = 0;while(left<right){mid = (left + right)/2;if(nums[mid]>nums[mid + 1]){right = mid;}else{left = mid + 1;}}return right;}
};
初看之下,面对问题好像难以着手,但让我们仔细分析一下,看看能否找到解决方案。
题目要求在数组中找到任意一个峰值,那么我们可以考虑将数组分为两个区间:一个是递增区间,另一个是递减区间。峰值实际上是这两个区间的交界点。
假设我们随机选择一个点进行比较,如果它比右侧位置的值小,说明它在一个递增的区间;反之,如果它比右侧位置的值大,说明它在一个递减的区间。
基于这个性质,我们可以运用二分算法。当 nums[mid] < nums[mid+1] 时,表示在一个递增区间,峰值必定在 mid+1 及其之后的位置;而当 nums[mid] > nums[mid+1] 时,表示在一个递减区间,峰值可能在 mid 或其之前的位置(需要注意,峰值有可能就是在 mid 位置)。
因此,我们更新 right = mid,而不需要进行 -1 的操作。由于不需要 -1,当 left == right 时,如果已经找到峰值,我们应该如何退出循环呢?
这里可以进行特殊处理,或者将循环条件改成 left < right。在某些情况下,模板并不是固定不变的,我们可以根据实际情况进行调整。通过解决这道题,我们不仅学到了一些技巧,也积累了宝贵的经验。
5.寻找旋转排序数组中的最小值(难度⭐⭐)
Leetcode链接:153. 寻找旋转排序数组中的最小值
5.1题目描述:
这题的解题思路与前面一道问题相似,我们需要根据所给的条件找到一个可以进行比较的参照物或者说参照系。让我们来审视一下具体的代码。
5.2代码:
class Solution {
public:int findMin(vector<int>& nums) {int n = nums.size() - 1;int left = 0, right = n, mid = 0;while(left < right){mid = (left + right)/2;if(nums[mid] > nums[n]){left = mid + 1;}else if(nums[mid] < nums[n]){right = mid;}}return nums[left];}
};
考虑到题目给出的是一个经过旋转的升序数组,这使得数组不再是有序的,我们需要思考如何运用二分法来解决这一问题。
观察到,经过旋转的升序数组可以分为两个递增的区间,一个较大的区间和一个较小的区间。我们可以以区间的最大值作为参照物来进行分析。
以最右边的元素为例,它可能是小区间的最大值,也可能是大区间的最大值。如果它是大区间的最大值,这就意味着数组没有经过旋转,因此我们可以先忽略这种特殊情况(这是一个解题的小技巧,特殊情况可以后续再处理)。
题目要求找到最小的元素,即小区间的最小值。因此,我们需要找到小区间,并在其中找到最小元素。具体操作如下:
- 当 nums[mid] > nums[n] 时,表示中间位置 mid 处于大区间,因此将 left 调整为 mid + 1;
- 当 nums[mid] < nums[n] 时,表示中间位置 mid 处于小区间,因此将 right 调整为 mid。注意,这里不能减1,因为我们要找的值在小区间内,不能排除掉中间元素。
- 接着,考虑特殊情况,即当 nums[mid] < nums[n] 时,数组的最右元素 n 是大区间的最大值。如果我们让 right = mid,会导致最终循环结束时出现 left = right 的情况。为了避免这种情况,我们将循环的条件调整为 left < right。
这道题是二分法的一个变式,关键在于找到以何为参照系来确定区间的位置,一旦确定,后续的工作就变得相对容易。
6.点名(难度⭐)
Leetcode链接:LCR 173. 点名
6.1题目描述:
这道题我其实一开始也想不出来,选这道题的目的其实也是想说明,算法积累的重要性,见多识广,才能思路开阔,临危不乱。
6.2代码:
class Solution
{
public:int takeAttendance(vector<int>& records) {int n = records.size() - 1;int left = 0, right = n, mid = 0;while(left < right){mid = (left + right)/2;if(records[mid] == mid){left = mid + 1;}else{right = mid;}}if (records[right] == right) {return right+1;}return right;}
};
总结一下:
完成了这六道题目后,相信你对二分查找已经得心应手了~
接下来,继续努力,迎接新的挑战吧~
如果有一天觉得对二分有些生疏了,不妨回来再刷一遍,巩固一下技能~
最后,祝愿你未来的刷题之路愉快顺利~
相关文章:

【LeetCode 算法专题突破】---二分查找(⭐⭐⭐)
前言 我在算法题目的海洋中畅游已久,也曾在算法竞赛中荣获佳绩。然而,我发现自己对于算法的学习,还缺乏一个系统性的总结和归类。尽管我已经涉猎过不少算法类型,但心中仍旧觉得有所欠缺,未能形成完整的算法体系。 因…...
一个简单的HTML 个人网页
<!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0"> <title>个人网页</title> <style> body { f…...
【SpringCloud微服务实战05】Feign 远程调用
Feign是一个由Netflix开发的轻量级RESTful HTTP服务客户端,用于简化和优雅地调用HTTP API。它允许用户通过Java接口注解来发起请求,而不必像传统方式那样手动构建HTTP请求报文。Feign支持Spring Cloud解决方案,使得服务消费者能够像调用本地接口方法一样调用远程服务。使得开…...

LiveGBS流媒体服务器中海康摄像头GB28181公网语音对讲、语音喊话的配置
LiveGBS海康摄像头国标语音对讲大华摄像头国标语音对讲GB28181语音对讲需要的设备及服务准备 1、背景2、准备2.1、服务端必备条件(注意)2.2、准备语音对讲设备2.2.1、不支持跨网对讲示例2.2.2、 支持跨网对讲示例 3、开启音频开始对讲4、搭建GB28181视频…...
【前端】尚硅谷Webpack教程笔记
文章目录 1. 基本使用1.1 功能介绍1.2 开始使用 参考视频:尚硅谷Webpack5入门到原理 课件地址 【前端目录贴】 1. 基本使用 1.1 功能介绍 Webpack 是一个静态资源打包工具。 它会以一个或多个文件作为打包的入口,将我们整个项目所有文件编译组合成一个或多个文件输…...
Java泛型使用及局限
Java泛型的局限和使用经验 泛型的局限 任何基本类型不能作为类型参数 经过类型擦除后,List中包含的实际上还是Object的域,而在Java类型系统中Object和基本类型是两套体系,需要通过“自动装包、拆包机制”来进行交互。 2.任何在运行时需要…...
Sklearn线性回归
Scikit-learn 中的线性回归是一个用于监督学习的算法,它用于拟合数据集中的特征和目标变量之间的线性关系。以下是使用 Scikit-learn 实现线性回归的基本步骤: 1. 导入所需库 首先,你需要导入所需的库和模块。 import numpy as np import …...

APP中互联网公司的必备知识
APP中互联网公司的必备知识 敏捷开发(scrum)模型角色工作流程 项目上线发布策略发布流程灰度发布 APP发布APP软件包类型APP客户端(内部)发布平台APP客户端(线上)发布平台 熟悉APP项目(tpshop&am…...
论文翻译 - Visual Adversarial Examples Jailbreak Large Language Models
论文链接:https://arxiv.org/pdf/2306.13213.pdf 项目代码:https://github.com/Unispac/Visual-Adversarial-Examples-Jailbreak-Large-Language-Models Visual Adversarial Examples Jailbreak Aligned Large Language Models Abstract1 Introduction2 …...
android so载入过程
源自android 9 看源代码的网页 /bionic/libdl/libdl_static.c 好像没用。都是空的 /bionic/libdl/libdl.cpp 主角 22// These functions are exported by the loader 23// TODO(dimitry): replace these with reference to libc.so101// Proxy calls to bionic loader 102_…...

FlowerShop花店管理系统wpf+sqlserver
FlowerShop花店管理系统wpfsqlserver说明文档 运行前附加数据库.mdf(或sql生成数据库) 主要技术: 基于C#wpf架构和sql server数据库 功能模块: 顾客登录后可以查询花卉详情然后购买 店主登录管理后台 顾客管理 删除顾客多行删…...

如何在群晖NAS部署WPS容器并实现无公网IP远程访问本地office软件
文章目录 1. 拉取WPS Office镜像2. 运行WPS Office镜像容器3. 本地访问WPS Office4. 群晖安装Cpolar5. 配置WPS Office远程地址6. 远程访问WPS Office小结 7. 固定公网地址 wps-office是一个在Linux服务器上部署WPS Office的镜像。它基于WPS Office的Linux版本,通过…...

【C语言程序设计】C语言求圆周率π(三种方法)
题目一: 利用公式①计求π的近似值,要求累加到最后一项小于10^(-6)为止。 程序代码: #include <stdio.h> #include <stdlib.h> #include <math.h> int main(){float s1;float pi0;float i1.0;float n1.0;while(fabs(i)&…...
常见的特殊端口号及其用途
21端口:FTP(文件传输协议)服务端口。FTP允许用户进行文件传输,如上传和下载文件。22端口:SSH(安全外壳协议)服务端口。SSH用于远程登录到服务器,并提供加密的数据传输。23端口&#…...
Linux(ubuntu) 安装kotlin
Kotlin 是一种基于 Java 语言的静态类型编程语言,它可以运行于 JVM 上 1. 安装 Java Development Kit (JDK) Kotlin 运行于 JVM 上,所以首先需要安装 Java Development Kit(JDK) Ubuntu 或 Debian 系统 sudo apt update sudo a…...
微信小程序提交成功设置提示
在微信小程序中,当用户成功提交表单或完成某项操作后,通常我们会设置一个提示来告知用户操作已完成。这种提示通常可以通过几种方式来实现,例如使用 wx.showToast 方法显示一个短暂的提示消息,或者跳转到一个新的页面并显示成功信…...

Pycharm与Anaconda安装
网址: Pycharm:https://www.jetbrains.com/pycharm/ Anaconda:https://www.anaconda.com/download/ 官网下载速度太慢可以选择到清华源下载:https://repo.anaconda.com/archive/ 一:Anaconda安装 安装: …...

阿里云数据盘挂载目录
1、先登录服务器创建新目录aaa 2、云盘都快照备份下。后续操作完核实无误了,您根据您需求删除快照就行, 然后登录服务器内执行: fdisk -l lsblk blkid ll /aaa 3、执行:(以下命令是进行数据盘做ext4文件系统并挂载到…...
【Python】探索PyPinyin 库:Python 中的中文拼音转换工具
花未全开月未圆, 半山微醉尽余欢。 何须多虑盈亏事, 终是小满胜万全。 —— 《对抗路—吕布》 PyPinyin 是一个功能强大的 Python 库,用于将中文文本转换为拼音。它提供了丰富的功能,能够满足各种中文文本处理的需求。在本文中&am…...
Linux运维总结:Centos7.6之OpenSSH7.4升级版本至9.3
一、环境信息 操作系统:Centos7.6.1810 OpenSSH_7.4p1, OpenSSL 1.0.2k-fips 注意:升级后由于加密算法的区别,低版本的SSH工具可能无法连接,建议改用Xshell7或SecureCRT9.0以上版本。 二、注意事项 1、 检查防火墙或selinux是否…...

深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

android RelativeLayout布局
<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...

stm32wle5 lpuart DMA数据不接收
配置波特率9600时,需要使用外部低速晶振...
人工智能 - 在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型
在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型。这些平台各有侧重,适用场景差异显著。下面我将从核心功能定位、典型应用场景、真实体验痛点、选型决策关键点进行拆解,并提供具体场景下的推荐方案。 一、核心功能定位速览 平台核心定位技术栈亮…...
书籍“之“字形打印矩阵(8)0609
题目 给定一个矩阵matrix,按照"之"字形的方式打印这个矩阵,例如: 1 2 3 4 5 6 7 8 9 10 11 12 ”之“字形打印的结果为:1,…...

Java后端检查空条件查询
通过抛出运行异常:throw new RuntimeException("请输入查询条件!");BranchWarehouseServiceImpl.java // 查询试剂交易(入库/出库)记录Overridepublic List<BranchWarehouseTransactions> queryForReagent(Branch…...