跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

二分查找与双指针算法实战:LeetCode 704、35、34、27、977

总结了二分查找的三种区间不变量模板及双指针技巧。通过 LeetCode 704、35、34 题实践二分查找的标准查找、插入位置及首尾定位;利用 27 题和 977 题演示快慢指针与头尾指针在移除元素及有序数组平方中的应用。重点在于理解边界条件与 mid 计算逻辑,避免死循环或越界。

内存管理发布于 2026/3/16更新于 2026/7/254 浏览
二分查找与双指针算法实战:LeetCode 704、35、34、27、977

704. 二分查找

模板题

状态:完全掌握三种模板

这题是模板题,用标准思路很快就能写出来,且易于记忆。

我给二分模板定了三要素进行记忆:1.左右初始化;2.while() 条件;3.mid 是否±1。

理解二分的边界是最容易记忆二分的,理解方法是区间不变量原则。为了方便,现在定义的数组都是从小到大顺序排序并且数组从 0 开始。

区间不变量是指将二分的 Left 和 Right 当成区间,同时固定为闭区间还是开区间的不变量。简单来说举个例子:(左闭右开)Left 是闭区间,Right 是开区间,Left 的值是可以取到的,但 Right 的值无法取到。首先看 1.左右初始化:左闭 left 时数组可以取到 left 值,所以 left=0 等于原数组的下标下限,右开 right 取不到,所以 right=nums.size() 比原数组的下标上限多 1 个;2.while() 条件:左闭 left 时数组可以取到 left 值,右开 right 时数组取值不到,right 不能=left 值,所以 while(left<right);3.mid 是否±1:左闭 left 时数组可以取值,此时 mid=left+right>>1,nums[mid]<target,left 更新,因为 mid 此时的值已经不符合 target 了并且是左闭 left 是可以取到的,所以 left 不取 mid,而是从 mid+1 开始,所以左闭 mid+1。同理,右开 right 时数组取不到 right 的值,nums[mid]>target,right 更新,mid 此时的值不符合 target 并且右开 right 的值是取不到的,所以 right 是可以取到 mid。那左闭右闭则 left=mid+1,right=mid-1;以此类推左开右开 left=mid,right=mid。

我做了个表格以此类推我的理解原则:

区间不变量左右初始化while() 条件mid 是否±1
左闭右开left=0 | right=nums.size()left<rightleft=mid+1
right=mid
左闭右闭left=0 | right=nums.size()-1left<=rightleft=mid+1
right=mid-1
左开右开left=-1 | right=num.size()left+1!=rightleft=mid
right=mid

最后一行是小金鱼的模板,我记忆为两边都是开的情况,是符合我们的区间不变量原则的,同时没有左开右闭这种情况是因为日常开发中都是用的左闭的多。

下面用左闭右开手撕模板题,模板题是默认了从小到大排列同时没有重复元素的:

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left=0,right=nums.size(),middle;
        while(left<right) {
            middle=left+(right-left)/; 
            (nums[middle]==target) middle;
             (nums[middle]>target)right=middle;
             left=middle;
        }
         ;
    }
};
2
//防止两个int相加爆int
if
return
else
if
else
+1
return
-1

35. 搜索插入位置

这题和上面的模板题变化的地方在于找不到 target 不是输出 -1 了,而是插入到原数组去。

我这里使用左开右开来写,使用分界线理论,可以看做是卡哥模板的衍生;我的个人详细理解在下一道题。

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int left=-1,right=nums.size(),middle;
        while(left+1!=right) {
            middle=left+right>>1;
            if(nums[middle]>=target)right=middle;
            else if(nums[middle]<target)left=middle;
        }
        return right;
    }
};

34. 在排序数组中查找元素出现第一次的位置和最后一次的位置

思路:把 mid 当成分界线,左边 left 都是小于 target,右边 right 都是大于等于 target 的,所以分界线右边第一个元素就是 target 第一次出现的位置,即此时 right 的下标;

同理当我的左边都是小于等于 target 的数,右边都是大于 target 的数,那分界线左边第一个元素就是 target 最后一次出现的位置,即此时 left 的下标;

手撕代码如下,用的左开右开:

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        if(nums.empty())return{-1,-1}; //当数组是空的时候直接结束输出 -1,-1
        int l1,r1,l2,r2;
        int ans1,ans2;
        l1=-1;l2=-1;r1=nums.size();r2=nums.size();
        while(l1+1!=r1) {
            int mid=l1+(r1-l1)/2;
            if(nums[mid]>=target)r1=mid;
            else l1=mid;
        }
        if(r1<nums.size()&&nums[r1]==target)ans1= r1;
        else return{-1,-1};
        while(l2!=r2-1) {
            int mid=l2+(r2-l2)/2;
            if(nums[mid]>target)r2=mid;
            else l2=mid;
        }
        if(nums[l2]==target)ans2=l2;
        // else ans2= -1; 这行可写可不写,因为第一个出现位置找不到就肯定找不到最后一个出现位置
        return {ans1,ans2};
    }
};

27. 移除元素

思路:双指针(快、慢指针)

这题在力扣是可以暴力写的,但时间复杂度是 O(n*n);

用双指针可以只用一层 for 循环,时间复杂度到 O(n);

由于数组在内存上是一段连续的地址,所以是不存在删除的,只能用后面的元素覆盖掉实现'删除'。所以我们可以用两个指针进行更新数组,快指针 fast 用于指向不删除的元素,慢指针 slow 指向我们的新数组,将 fast 指向的值给 slow 即可完成更新。具体代码如下:

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int size = nums.size();
        for(int fast=0,slow=0;fast<nums.size();fast++) {
            if(nums[fast]!=val) {
                nums[slow++]=nums[fast];
            } else size--;
        }
        return size;
    }
};

977. 有序数组的平方

思路:双指针(头、尾指针)

暴力写法可以直接全部平方之后再 sort 排序,但因为 sort 复杂度是 O(nlogn) 的,还能再优化。

用空间换时间,再开一个新数组,因为存在负数的平方是大于正数的,而且原数组是有序排列的,所以可以头尾各设计一个指针,平方值大的更新在新数组的末尾,这样只用一次循环,代码时间复杂度 O(n),代码如下:

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        int left=0,right=nums.size()-1;
        int k=nums.size()-1;
        vector<int>num(nums.size());
        while(left<=right) {
            if(pow(nums[left],2)<pow(nums[right],2)) {
                num[k--]=pow(nums[right],2);
                right--;
            } else {
                num[k--]=pow(nums[left],2);
                left++;
            }
        }
        return num;
    }
};

二分还是很建议大家琢磨透再写的,很重要的算法。

目录

  1. 704. 二分查找
  2. 35. 搜索插入位置
  3. 34. 在排序数组中查找元素出现第一次的位置和最后一次的位置
  4. 27. 移除元素
  5. 977. 有序数组的平方
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 扩散模型详解:从DDPM到Stable Diffusion再到DiT的技术演进
  • Mac mini M4 部署 OpenClaw + Ollama 本地大模型接入飞书机器人
  • Phi-3-mini-4k-instruct 多场景应用:邮件/逻辑/代码生成详解
  • Obsidian 同步新方案:坚果云官方插件免 WebDAV 配置及冲突合并
  • 动态规划详解:不同路径问题解析
  • 未来哪些行业与岗位面临机器人替代风险?
  • Qwen3-VL WebUI 详解:支持视频理解与 GUI 操作
  • Python diskcache 磁盘缓存工具使用指南
  • Kubernetes 与边缘 AI 最佳实践
  • B 站 PC 端自动开启字幕用户脚本
  • 2026 年编程语言排行:Python 稳居榜首,Rust 强势崛起
  • 解决 Java 编译报错:源发行版 17 需要目标发行版 17
  • RTX 4090 本地部署腾讯混元与阿里通义万相视频生成模型
  • 六自由度机器人逆运动学详解与 Matlab 实现
  • Continue插件实现本地部署一个“cursor”或“github copilot”
  • iOS 26 系统兼容适配:UITabBar 液态玻璃效果与 WiFi SSID 获取
  • 论文AI率多少算正常?各高校AIGC检测标准汇总
  • 无需部署服务器,利用内网穿透实现本地服务对外演示
  • Mac mini M4 部署 OpenClaw + Ollama 本地大模型接入飞书机器人
  • 【实战】从零搭建GEO多平台监控系统:支持ChatGPT、豆包、Kimi、文心一言

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online