要写出优雅的二分查找实属不易(C++,LeetCode34)

Java二分查找算法面试题全解析:模板、边界条件与变体练习 二分查找(Binary Search)是算法与数据结构中的基础搜索策略,核心原理是利用有序序列的单调性,每轮比较将搜索区间缩小一半,从而将时间复杂度从线性降至对数级。这种高效的查找方式在Java面试中极为常见,尤其是在LeetCode等在线评测平台上,围绕边界条件、循环不变量、整数溢出等细节衍生出大量变体题目。从标准数组查找,到搜索插入位置、旋转排序数组,再到二分答案法解决最值问题,掌握二分算法的本质不仅能应对面试中的手写代码环节,也是提升工程实践中定位与搜索效率的关键。本文以Java语言为背景,系统梳理二 阅读详情

先说句废话:我个人比较喜欢左闭右开区间,所以这里仅展示左闭右开区间的代码......

废话不多说先看题:(来源于leetcode)在排序数组中查找元素的第一个和最后一个位置


想都不用想,有序数组,显然二分。

于是我就开始敲代码

敲代码

敲代码

敲完过一下示例

啪!解错。

改完再过

啪!超时。

改完再过

啪!越界。

······

(事实证明stl的lower_bound和upper_bound虽然很好用,但是没事练练写二分还是很重要的。。。)

虽然最后,代码还是过了。但是···真的不堪入目:

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        if(nums.size()<1)
            return {-1,-1};
        int left = 0,right = nums.size();
        while(left<right){
            int mid = (left+right)/2;
            if(nums[mid]>=target)
            {
                right = mid;
            }
            else if(nums[mid]<target)
            {
                left = mid+1;
            }
        }
        int res1 = right;
        if(res1>=nums.size()||nums[res1]!=target)
            res1 = -1;
         left = 0,right = nums.size();
        while(left<right){
            int mid = (left+right)/2;
            if(nums[mid]>target)
            {
                right = mid;
            }
            else
            {
                left = mid+1;
            }
        }
        int res2 = left+1<nums.size()&&nums[left]==target?left:left-1;
        if(res2<0||nums[res2]!=target)
            res2 = -1;
        return {res1,res2};
    }
};

 (啊啊啊啊啊啊啊·····································)


那么到底怎么才能写出优雅的二分查找呢?

(这里就拿左闭右开区间的写法作为展示,其实这个搞明白了左闭右闭区间也能很好的写出来。)

记住一点:先明确思路,再动手去做,并且时刻明白自己在做什么。

首先,根据二分法的思想,每一次取mid = left +(right-left)>>1 ,由于我们确定的是[left,right) 区间,

所以,如果数组元素数量是奇数,所得的mid对应的元素便是中间元素;

如果数组元素数量是偶数,所得的mid对应的元素其实是中间偏 右 的元素。

其次要注意,每一次更新左右端点,都要保证区间能变小能够使得循环跳出,否则会导致死循环。

 好的,然后我们要做的就是在二分查找的大框架中一步一步填补空缺:

(以下代码的注释便是思考的过程)

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        if(nums.size()==0)
            return {-1,-1};     //这个特判是必要的,因为后面免不了需要判断是否存在(否则24,40行处会出问题),
        //*******************
        int left = 0,right = nums.size(); //区间的左右
        int res1,res2;                    //用来分别记录两次查找的答案
        //***********************************
        while(left<right){                //先找最靠前的target
            int mid = left+((right-left)>>1); //每一次循环都要取mid,即此区间中间的数,
                                            //若区间内元素为奇数,则mid代表最中间的数,偶数的话就是最中间偏右的数
            if(nums[mid]<target){           //如果nums[mid]小于target  则说明[0,mid]区间内都没有target 则使left = mid+1
                left = mid+1;  
            }else if(nums[mid]>target){     //如果nums[mid]大于target  则说明[mid,right)区间内都没有target 则使right = mid
                right = mid;
            }else{          //若nums[mid]等于target 说明最靠【前】的target在 [left,mid]内   本应该使right = mid+1
                                        //但是此时考虑到如果right = mid+1  可能会导致死循环 比如搜索区间:[1,2,3) target = 2时 right就不变了
                 right = mid;           //所以暂且先令right = mid;
                                        //因为这样的话,如果mid前面没有target的话,答案就是这里的right(并且此后right不会再移动)  如果有的话 也会在【更新后】的[left,right)区间内
            }                           //最后思考一下,如果循环跳出时是什么情况————是left == right(因为我们的更新区间的方式,所以不会出现left>right)
        }                               //而此时left ==right就是我们要的答案吗? 不一定!因为可能target不在nums内
                                        //但是如果存在的话,由上面咱们缜密地缩小区间可知,target肯定跑不掉,一定是现在的right,不要想些其他的有的没的了。
        res1=right<nums.size()&&nums[right]==target?right:-1;  //所以最后判断下是否存在即可  但是此时要注意 因为我们是左闭右开区间 如果right没动的话 right 就越界了
                                                                //所以要加一个判断条件right<nums.size()
        //************************************
        left = 0,right = nums.size();
        while(left<right) //再找最靠后的target
        {                 //思考过程同上
            int mid = left +((right -left)>>1);
            if(nums[mid]<target){
                left = mid+1;
            }else if(nums[mid]>target){
                right = mid;
            }else{                 //主要是这里不同,若nums[mid]等于target  说明最靠【后】的target在[mid,right)内 所以移动left短点
                                   //但是此时考虑到如果left = mid  可能会对导致死循环 比如搜索区间[1,2) target = 2 时 left就不变了
                left = mid +1;     //所以暂且先令left = mid +1;
                                   //因为这样的话,如果mid后面没有target的话,答案就是这里的 left-1 如果有的话 也会在【更新后】的[left,right)区间内
            }
        }                          //由缩小方式可知结束时一定是left == right
        res2 = left-1>=0&&nums[left-1]==target?left-1:-1;//判断是否存在  注意!!由于是判断下标left-1    所以如果left==0的话会爆掉 
                                                         //所以要加一个判断条件:left-1>=0  (注意 因为这里是left-1也是right-1所以不用担心会大于等于nums.size())
        //********************************************************
        return {res1,res2};        //输出答案 结束
    }
};

条理清楚,一般就会减少混乱及其带来的麻烦。

然后,考虑到如果查找不到target的话 可以直接输出{-1,-1},于是还可以做点优化

最后合并一下nums[mid]==target的情况

得到改进版代码:

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        if(nums.size()<=0) return {-1,-1};
        int left = 0,right = nums.size();
        int res1,res2;
        while(left<right)
        {
            int mid = left+((right-left)>>1);
            (nums[mid]<target)?left=mid+1:right = mid;
        }
        if(right==nums.size()||nums[right]!=target)
            return {-1,-1};
        else 
            res1 = right;
        left = 0,right = nums.size();
         while(left<right)
        {
            int mid = left+((right-left)>>1);
            (nums[mid]<=target)?left=mid+1:right = mid;
        }
        if(right==0||nums[right-1]!=target)
            return {-1,-1};
        else 
            res2 = right-1;
        return {res1,res2}; 
    }
};

结束 

 

人脑直觉 vs CPU指令:程序员的底层思维校准指南 程序运行的本质,是高级语言逻辑向硬件执行单元的映射过程。理解CPU如何基于寄存器、内存地址和时钟周期完成ADD、LOAD、CMP等原子操作,是突破算法记忆瓶颈与性能幻觉的关键。本文从人脑并行视觉处理与CPU串行指令流的根本差异切入,解析编译器如何将C代码翻译为汇编,揭示高速缓存预取、栈帧管理、内存访问模式等物理约束对实际性能的决定性影响。通过线性查找与二分查找的纳秒级对比、旋转数组的机械式拆解、线上`memcmp`雪崩故障复盘等真实案例,阐明‘为硅而写’而非‘为人而读’的工程实践准则。核心聚焦于寄存器资源限 阅读详情

相关推荐

2026华为OD机考新系统真题 + 双机位C卷 + 往年真题 - 题库目录分值说明 + 考点说明+在线OJ

2026年4月1日起,华为OD机试正式切换至新系统模式!采用力扣模式,无需自己写输入! 难度大幅度降低。正在备考华为OD机试的同学,优先刷新系统机试真题,可大幅提升通过率。 新系统考题考点与旧版一致,无需重新适应。本专栏所有算法题均配有详细思路解析,并提供C语言、JS、C++、Python、Go、Java多语言源码实现。订阅后私信即可开通专属OJ刷题权限,高效备考一次上岸!

算法大师! 45万+

LeetCode Hot 100 二分查找篇 - 每次砍一半,六道题从入门到穿透

这篇文章介绍了LeetCode Hot 100中的6道二分查找题目,从基础到进阶逐步深入讲解。主要内容包括: 基础模板题(LC35):介绍标准二分查找实现,重点分析循环结束时左右指针的位置关系。 二维矩阵搜索(LC74):将有序二维矩阵展平为一维数组进行二分查找。 查找元素范围(LC34):使用lower_bound技巧优雅地找到目标值的起始和结束位置。 旋转数组搜索(LC33):利用"必有一半有序"的特性,在旋转后的有序数组中进行二分查找。 文章通过生动的比喻(如字典查找)和清晰的图示

2301_76728354的博客 390

2026华为OD机试(C语言)真题【E卷+A卷+B卷+C卷+D卷】目录+在线OJ

华为OD机试真题题库【E卷+A卷+B卷+C卷+D卷】目录,C语言实现。

MISAYAONE的博客 11万+

LeetCode 34题精讲:二分查找边界与lower_bound/upper_bound

二分查找是处理有序数组的高效算法,能在O(log n)时间内定位目标。然而当数组中存在重复元素时,普通的二分查找无法直接返回元素的首次和末次出现位置,这时需要借助lower_bound和upper_bound两个边界查找技巧。通过理解循环不变量和左闭右开区间,可以清晰掌握边界收缩的规律,避免死循环和越界错误。该技术广泛应用于有序数据检索、区间统计、插入位置查找以及旋转数组等问题。本文以LeetCode 34题为例,深入剖析排序数组中查找元素第一个和最后一个位置的完整思路与可复用模板。

weixin_33282146的博客 264

2026华为OD机试(Python)真题【E卷+A卷+B卷+C卷+D卷】目录+在线OJ

华为OD机试真题题库【E卷+A卷+B卷+C卷+D卷】目录,Python实现。

MISAYAONE的博客 29万+

2026华为OD机试(JAVA&Go)真题【E卷+A卷+B卷+C卷+D卷】目录+在线OJ

华为OD机试真题题库【E卷+A卷+B卷+C卷+D卷】目录,Java实现。

MISAYAONE的博客 34万+

Binary Search 二分查找算法:逻辑的舞蹈,二分法的精准步伐

二分查找算法,也称为二分搜索算法(Binary Search),是一种在有序数组中查找特定元素的高效算法。它通过反复将搜索区间减半来快速定位目标值。二分查找算法的效率远高于线性搜索,因为它每次比较都能排除掉一半的搜索空间。

Yi-Hawk's Blog 883

2026华为OD机试(JavaScript)真题【E卷+A卷+B卷+C卷+D卷】目录+在线OJ

华为OD机试真题题库【E卷+A卷+B卷+C卷+D卷】目录,JavaScript实现。

MISAYAONE的博客 8万+

二分查找算法详解:从基础模板到边界问题实战

二分查找是一种在有序数据集中高效查找目标值的算法,其核心原理是通过不断将搜索区间对半分割,将时间复杂度从线性 O(n) 优化至对数 O(log n)。该算法的技术价值在于其高效性和广泛的应用基础,是算法学习与面试中的关键考点。理解循环不变式与搜索区间(如左闭右闭 [left, right] 或左闭右开 [left, right))的定义,是保证代码正确性的基石。在实际工程中,二分查找不仅用于精确匹配,更常见于处理边界问题,例如在有序数组中寻找目标值的首次或末次出现位置,这需要掌握通用的“寻找第一个满足条件的

weixin_34054866的博客 358

Python Selenium调用IE11报错全解析:从环境配置到稳定运行

在Web自动化测试领域,Selenium作为主流的跨浏览器测试框架,其核心原理是通过WebDriver协议与不同浏览器的驱动程序进行通信,实现对浏览器行为的模拟与控制。这一技术为软件测试的自动化、回归测试的效率提升提供了重要价值,广泛应用于金融、政务等对遗留系统兼容性要求高的行业场景。然而,当技术栈涉及过时的浏览器如IE11时,环境配置的复杂性显著增加,特别是Python与Selenium的组合常遭遇驱动兼容性、安全设置等挑战。本文聚焦于解决Python Selenium驱动IE11时的典型报错问题,深入剖

weixin_28834765的博客 322

晟矽微MC32F7361定时器的使用案例说明

110所以TIMER0所用的频率是FCPU的1/64,也就是8/64MHZ. 为1/8MHZ。//io口下拉电阻 1:enable 0:disablea。//io口上拉电阻 1:enable 0:disable。//io口下拉电阻 1:enable 0:disable。//io口上拉电阻 1:enable 0:disable。//io口下拉电阻 1:enable 0:disable。//io口上拉电阻 1:enable 0:disable。

liyanfei123456的博客 1129

[Leetcode]34.Search for a Range

[Leetcode]34.Search for a Range

BBbird_Miao的专栏 353

深入解析HAL_UART_Receive_IT:如何高效配置串口中断接收

本文深入解析了STM32 HAL库中`HAL_UART_Receive_IT`函数的工作原理与高效配置方法。该函数并非直接接收数据,而是作为中断接收的启动器和配置器,通过开启相关中断,由`UART_Receive_IT`在后台完成数据搬运。文章详细对比了中断与轮询模式的区别,并提供了不定长数据接收的完整实战流程、常见问题避坑指南及高级应用技巧,帮助开发者构建稳定高效的串口通信。

weixin_29162439的博客 635

程序员的算法趣题:Q40 优雅的IP地址(Java版)

前提知识 IPv4:32bit(二进制形式)或 192.168.1.2(十进制形式) 题目链接(力扣网):https://leetcode-cn.com/leetbook/read/interesting-algorithm-puzzles-for-programmers/9i00p1/ 题目要求 1.二进制形式:左右对称,比如11111111000000000000000011111111 2.十进制形式:0~9均出现,且不重复 思路一 左侧共16bit,即16个二进制位,共有65536种情

lanying100的博客 268

2080Ti双卡开启NVLink

本文介绍了如何在Ubuntu 22.04系统下给2080Ti双卡开启NVLink的方法。

flymyd的博客 2900

TI毫米波雷达人体生命体征(呼吸、心跳)信号提取算法(IWR6843ISK+DCA1000EVM)

本篇内容介绍的算法主要为传统的提取算法,但可实现在1m内呈现良好的检测效果,能够提取出非常可观的呼吸和心跳波形,但在超出1m的距离后便不适用这个算法了。远距离检测呼吸和心跳始终是这个领域一个很大的挑战。要实现远距离检测可在提取相位信号、分离呼吸和心跳信号上进行改进处理,例如线性解调提取相位、改进的VMD分离呼吸和心跳算法。

m0_61934621的博客 3万+

2026年数据结构与算法学习指南:从入门到精通,程序员的必修之路

2026年,数据结构与算法仍是程序员核心竞争力。本文提供从零到面经通关的5阶段学习路径:基础夯实(1-2月)、理论攻坚(2-3月)、模式识别(3-4月)、面试实战(长期)、查漏补缺(冲刺)。涵盖数组、链表、哈希表、二叉树、动态规划等十大专题,配套Mermaid图解、代码模板与LeetCode高频题。推荐以“代码随想录+LeetCode Hot 100”为主线,按序刷题,3个月内实现算法能力质变。

热爱技术与前沿创新,深耕科技领域,在科创中精进自我;探索技术乐趣,分享技术干货与成长心得,以技术为伴,热爱生活,在科创与生活中双向成长。 328

AD9026芯片开发实战:从Example Code到API调用的关键步骤解析

本文详细解析了AD9026芯片开发的核心流程,重点阐述了如何从官方提供的Example Code入手,逐步理解硬件平台发现、HAL层初始化、配置加载、芯片复位、固件启动、JESD链路建立等关键API调用序列。通过剖析示例工程的结构与核心文件,为开发者在自定义硬件平台上移植和调试AD9026驱动提供了清晰的实战指南。

java5的博客 788

旋转图像LeetCode 48题:原地旋转矩阵的两种解法与面试技巧

矩阵旋转是图像处理和算法面试中的经典问题,其核心在于理解坐标映射关系:顺时针旋转90度后,元素从(i,j)移动到(j, n-1-i)。原地旋转要求在不使用额外矩阵的情况下完成,这对空间复杂度提出了严格约束。本文从坐标映射原理出发,系统介绍两种主流解法:一是通过转置加水平翻转将旋转拆解为两步,易于记忆且代码简洁;二是逐层四数轮换,直接实现原地交换。两种方法的时间复杂度均为O(n²),空间O(1)。文章还分析了常见的边界条件错误(如转置循环起点、翻转API选择)以及面试官常问的变体(逆时针旋转、180度旋转、非

weixin_30843121的博客 266

库存优化技术提升电商效率

第一部分:库存优化技术基础 第1章:库存优化的基本概念 库存优化是现代电商运营中至关重要的一个环节。简单来说,库存优化指的是通过一系列的策略和技术手段,使得库存管理更加高效、准确,从而降低运营成本,提高销售额。 1.1 库存优化的定义与重要性

AI天才研究院 1248

【好玩的游戏项目】使用Docker快速部署属于你的RPG网页小游戏

【好玩的游戏项目】使用Docker快速部署属于你的RPG网页小游戏

jks212454的博客 5577

PTA 编程题(C语言)-- 数字奇偶分类实战

本文以PTA编程题“数字奇偶分类”为例,详细讲解了使用C语言解决此类问题的核心思路与实战技巧。文章从基础的双计数器法入手,逐步深入到单计数器优化与位运算判断,并探讨了不同输入格式下的应对策略,旨在帮助读者掌握数据处理的基本流程与代码效率优化方法,为后续解决更复杂的PTA编程题打下坚实基础。

weixin_29014237的博客 110

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

数据结构与算法核心精讲:从概念到代码实战

数据结构与算法是计算机科学的基础,它们定义了数据的组织、存储和操作方式,是构建高效软件的核心。其原理在于通过特定的逻辑结构(如线性表、树、图)和算法策略(如分治、动态规划),在时间与空间复杂度之间进行权衡,以优化程序性能。掌握这些基础概念的技术价值在于,能够显著提升代码效率、解决复杂问题,并优化系统资源使用。在应用场景上,从数据库索引(B+树)、缓存系统(哈希表)到路径规划(图算法),数据结构与算法无处不在。本文聚焦于**链表**、**栈**、**队列**、**二叉搜索树**和**哈希表**等核心结构的实现

weixin_30644369的博客 643

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

[面试真题] LeetCode:Remove Nth Node From End of List

Given a linked list, remove thenthnode from the end of list and return its head. For example, Given linked list: 1->2->3->4->5, and n = 2. After removing the second node from ...

weixin_30509393的博客 73

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

C语言实现斐波那契数列:三大方法与溢出排查实战

斐波那契数列是算法入门与C语言编程练习中的经典问题,其递推关系背后隐藏着变量类型、循环控制、函数调用、数组边界等一系列基础知识点。本文从数学建模出发,梳理迭代、数组、递归三种主流实现方式的原理与适用场景,重点分析int与long long类型选择、递归效率瓶颈、记忆化优化技巧以及printf格式化输出的工程细节。针对初学者高频踩坑的数据溢出、边界处理、scanf校验等问题,结合常见错误速查表给出可落地的排查方案。无论你是准备面试或笔试,还是需要在嵌入式开发或数据处理中套用滚动更新思想,这套从建模到代码的完整

weixin_34355559的博客 161

LeetCode-Trapping Rain Water

又是这种需要仔细考虑的题目, 很容易就会漏掉一些情况,哎,感冒了, 完全不在状态,调了好几个小时, 写代码的能力实在是不行,总感觉写出来的代码不够优雅, 1 class Solution { 2 public: 3 int trap(int A[], int n) { 4 // Start typing your C/C++ soluti...

weixin_30770783的博客 79
上一篇: 如果你scrapy startproject报错找不到某个库,安装还找不到这个库,可能是因为这个原因
下一篇: 用Python的tkinter库做一个简单的打包作业的工具
咖啡咖_CoffCa
博客等级 码龄6年 116粉丝 58原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咖啡咖_CoffCa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值