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

Java 二分查找算法实战:从基础到进阶

综述由AI生成二分查找利用有序数组的二段性,将时间复杂度优化至 O(log N)。通过七个经典例题,涵盖标准查找、边界定位、平方根计算、插入位置及峰值寻找等场景。重点讲解如何根据单调性调整左右指针边界,处理溢出风险,并对比了哈希、遍历等其他解法在特定问题中的优劣,帮助读者掌握二分法的变体应用。

极光发布于 2026/3/15更新于 2026/6/1024 浏览
Java 二分查找算法实战:从基础到进阶

二分算法核心思路

二分查找的核心在于利用数据的二段性。在一个有序数组中,如果某个条件成立,其左侧(或右侧)必然满足某种规律,从而可以舍弃一半空间。相比暴力遍历的 O(N),二分能将复杂度降至 O(log N)。

1. 标准二分查找

在有序数组中查找目标值 target,找到返回下标,否则返回 -1。

class Solution {
    public int search(int[] nums, int target) {
        // left 和 right 分别指向当前搜索区间的两端
        int left = 0;
        int right = nums.length - 1;
        
        while (left <= right) {
            // 防止整数溢出
            int mid = left + (right - left) / 2;
            
            if (target > nums[mid]) {
                // 目标在右半部分 [mid+1, right]
                left = mid + 1;
            } else if (target < nums[mid]) {
                // 目标在左半部分 [left, mid-1]
                right = mid - 1;
            } else {
                return mid;
            }
        }
        return -1;
    }
}

注意:循环条件是 left <= right,因为当 left == right 时区间内仍有一个元素需要检查。

2. 在排序数组中查找元素的第一个和最后一个位置

题目要求找到目标值的起始和结束下标。由于存在重复元素,不能直接套用标准二分,需要分别寻找左边界和右边界。

  {
     [] searchRange([] nums,  target) {
        [] ret =  [];
        ret[] = ret[] = -;
         (nums.length == ) {
             ret;
        }
        
        
           ;
           nums.length - ;
         (left < right) {
               left + (right - left) / ;
             (nums[mid] < target) {
                left = mid + ;
            }  {
                right = mid;
            }
        }
         (nums[left] != target) {
             ret;
        }
        ret[] = left;
        
        
        left = ;
        right = nums.length - ;
         (left < right) {
            
               left + (right - left + ) / ;
             (nums[mid] > target) {
                right = mid - ;
            }  {
                left = mid;
            }
        }
        ret[] = right;
         ret;
    }
}
class
Solution
public
int
int
int
int
new
int
2
0
1
1
if
0
return
// 寻找左边界
int
left
=
0
int
right
=
1
while
int
mid
=
2
if
1
else
if
return
0
// 寻找右边界
0
1
while
// 向上取整,避免死循环
int
mid
=
1
2
if
1
else
1
return

3. x 的平方根

求 sqrt(x) 的整数部分。这属于'答案具有单调性'的场景,可以在 [0, x] 范围内进行二分。

class Solution {
    public int mySqrt(int x) {
        if (x < 1) {
            return 0;
        }
        // 使用 long 防止乘法溢出
        long left = 1;
        long right = x;
        while (left < right) {
            long mid = left + (right - left + 1) / 2;
            if (mid * mid <= x) {
                left = mid;
            } else {
                right = mid - 1;
            }
        }
        return (int) left;
    }
}

4. 搜索插入位置

在升序数组中找到目标值的位置,若不存在则返回应插入的位置。本质是寻找第一个大于等于 target 的元素。

class Solution {
    public int searchInsert(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 {
                right = mid;
            }
        }
        // 处理所有元素都小于 target 的情况
        return nums[right] < target ? right + 1 : right;
    }
}

5. 山脉数组的峰顶索引

山脉数组先增后减,峰值即为最大值。利用单调性,比较中间元素与其右侧元素即可判断峰值在哪一侧。

class Solution {
    public int peakIndexInMountainArray(int[] arr) {
        int left = 0;
        int right = arr.length - 1;
        while (left < right) {
            int mid = left + (right - left + 1) / 2;
            if (arr[mid - 1] < arr[mid]) {
                // 处于上升段,峰值在右侧
                left = mid;
            } else {
                // 处于下降段,峰值在左侧
                right = mid - 1;
            }
        }
        return left;
    }
}

6. 寻找峰值

任意一个峰值均可。只要 nums[i] != nums[i+1],数组中必然存在峰值。比较 mid 与 mid+1 可确定方向。

class Solution {
    public int findPeakElement(int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] > nums[mid + 1]) {
                // 下降趋势,峰值在左侧(含 mid)
                right = mid;
            } else {
                // 上升趋势,峰值在右侧
                left = mid + 1;
            }
        }
        return left;
    }
}

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

原有序数组经过旋转,分为两段递增序列。以最后一个元素为基准,可以将数组分为 > nums[n-1] 和 <= nums[n-1] 两部分。

class Solution {
    public int findMin(int[] nums) {
        int right = nums.length - 1;
        int n = right;
        int left = 0;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] > nums[n]) {
                // 最小值在右侧
                left = mid + 1;
            } else {
                // 最小值在左侧(含 mid)
                right = mid;
            }
        }
        return nums[left];
    }
}

8. 点名(缺失数字)

给定递增数组,下标与值一一对应,找出缺失的那个数字。除了哈希、求和、位运算外,二分法同样适用。

class Solution {
    public int takeAttendance(int[] records) {
        int left = 0;
        int right = records.length - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (records[mid] == mid) {
                // 前半部分正常,缺失在右侧
                left = mid + 1;
            } else {
                // 后半部分异常,缺失在左侧(含 mid)
                right = mid;
            }
        }
        return records[left] == left ? left + 1 : left;
    }
}

其他解法如哈希表、直接遍历、求和公式等虽然可行,但在数据量较大时效率不如二分查找稳定。掌握二分的变体逻辑,比死记硬背代码更重要。

目录

  1. 二分算法核心思路
  2. 1. 标准二分查找
  3. 2. 在排序数组中查找元素的第一个和最后一个位置
  4. 3. x 的平方根
  5. 4. 搜索插入位置
  6. 5. 山脉数组的峰顶索引
  7. 6. 寻找峰值
  8. 7. 寻找旋转排序数组中的最小值
  9. 8. 点名(缺失数字)
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

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

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

更多推荐文章

查看全部
  • MCP Server 插件:将 Dify 工作流发布为第三方可调用服务
  • Browser-Use 本地部署及远程访问自动化方案
  • 深入理解 Linux 基础 IO:从 C 库到系统调用
  • 位图矢量化技术瓶颈突破:Potrace 算法深度解析与应用实践
  • Python 工厂模式封装 Webhook 群聊机器人
  • HOS-MAKE:AI 驱动的代码加密与混淆系统
  • 动态规划入门:线性 DP 四道经典题解析
  • C++ 基础教程:从 Hello World 到变量类型
  • VS Code 远程开发 GitHub Copilot 失效排查指南
  • RabbitMQ 消息可靠性进阶:Confirm、持久化与幂等落地
  • Go 命令行 AI 对话客户端开发:从环境部署到核心实现
  • Android 版 Kotlin 协程入门进阶实战:基础应用
  • SpringBoot 整合轻量级安全框架 JWE 项目实战
  • 前端应用监控方案与最佳实践
  • Python 在 CentOS 系统上的安装、配置与部署深度指南
  • Python 使用 Selenium 实现网页自动化操作指南
  • 延凡 AI 工业视觉分析平台:制造业质检与效率优化方案
  • CLI-Anything:让所有软件都能被 AI Agent 原生调用
  • Sirius 开源漏洞扫描工具部署指南
  • AI 产品经理工作全流程与模型构建实战指南

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

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

  • Gemini 图片去水印

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