Java二分算法题目练习

Java 二分查找(Binary Search) 是算法面试和刷题中最核心、最常考的技巧之一。
它将查找时间从 O(n) 降到 O(log n),但写对细节非常考验边界处理能力。

下面我给你一套由浅入深的练习路线 + 经典题目 + Java 代码模板 + 常见变体 + 易错点总结,适合从入门到精通。

1. 二分查找核心模板(必背三种写法)

模板1:标准查找(找任意一个位置)
(LeetCode 704 模板)

// 返回 target 的索引,不存在返回 -1
public int binarySearch(int[] nums, int target) {
    int left = 0;
    int right = nums.length - 1;        // 注意:right 是闭区间

    while (left <= right) {             // 注意:<=
        int mid = left + (right - left) / 2;  // 防溢出

        if (nums[mid] == target) {
            return mid;
        } else if (nums[mid] < target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    return -1;
}

模板2:查找左边界(第一个 >= target 的位置)
(最常用变体)

// 返回 >= target 的最左位置,找不到返回 nums.length
public int leftBound(int[] nums, int target) {
    int left = 0;
    int right = nums.length;            // 注意:开区间,right 可取到 length

    while (left < right) {
        int mid = left + (right - left) / 2;

        if (nums[mid] < target) {
            left = mid + 1;
        } else {
            right = mid;                // 收缩右边界
        }
    }
    return left;                        // left 就是答案
}

模板3:查找右边界(最后一个 <= target 的位置)

public int rightBound(int[] nums, int target) {
    int left = 0;
    int right = nums.length;

    while (left < right) {
        int mid = left + (right - left) / 2;

        if (nums[mid] <= target) {
            left = mid + 1;             // 收缩左边界
        } else {
            right = mid;
        }
    }
    return left - 1;                    // 注意 -1
}

一句话记忆

  • 任意位置 → while(left <= right),找到就返回
  • 左边界 → 收缩右边界(right = mid),最后 left 就是答案
  • 右边界 → 收缩左边界(left = mid + 1),最后 left – 1 就是答案

2. 推荐练习顺序(由易到难,LeetCode 编号)

阶段1:基础(掌握模板)

    1. 二分查找(Easy)
    1. 搜索插入位置(Easy) ← 就是左边界模板
    1. 第一个错误的版本(Easy) ← 经典左边界

阶段2:左右边界 + 计数

    1. 在排序数组中查找元素的第一个和最后一个位置(Medium) ← 必做!
  1. 704 的变形:统计某个数出现次数(用左右边界相减 + 1)

阶段3:旋转数组 + 特殊二分

    1. 搜索旋转排序数组(Medium)
    1. 寻找旋转排序数组中的最小值(Medium)
    1. 搜索旋转排序数组 II(Medium) ← 有重复元素
    1. 寻找旋转排序数组中的最小值 II(Hard) ← 有重复

阶段4:二维矩阵 + 变种

    1. 搜索二维矩阵(Medium) ← 先找行,再找列
    1. 搜索二维矩阵 II(Medium) ← 从右上角开始的“伪二分”
    1. 有序矩阵中第 K 小的元素(Medium)

阶段5:二分答案(最重要进阶)

    1. 爱吃香蕉的珂珂(Medium) ← 经典二分答案
    1. 在 D 天内送达包裹的能力(Medium)
    1. 分割数组的最大值(Hard)
    1. 分享巧克力(Hard)
    1. 制作 m 束花所需的最少天数(Medium)

阶段6:综合 / 变形

    1. x 的平方根(Easy) ← 浮点二分或整数二分
    1. 寻找峰值(Medium) ← 二分 + 单调性
    1. 山脉数组的峰顶索引(Medium)
  1. 4. 寻找两个正序数组的中位数(Hard) ← 二分 + 划分

3. 经典题目 Java 完整代码示例(34题)

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] ans = new int[]{-1, -1};
        if (nums == null || nums.length == 0) return ans;

        // 找左边界
        int left = leftBound(nums, target);
        if (left == nums.length || nums[left] != target) {
            return ans;
        }

        // 找右边界
        int right = rightBound(nums, target);

        ans[0] = left;
        ans[1] = right;
        return ans;
    }

    private int leftBound(int[] nums, int target) {
        int left = 0, right = nums.length;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] < target) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return left;
    }

    private int rightBound(int[] nums, int target) {
        int left = 0, right = nums.length;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] <= target) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return left - 1;
    }
}

4. 常见易错点 & 防坑指南

  1. while (left <= right) 还是 < ?
    → 标准找元素用 <=,边界用 <
  2. mid = (left + right) / 2 还是 left + (right – left)/2 ?
    → 永远用后者,防止 int 溢出
  3. right = nums.length 还是 length-1 ?
    → 边界模板用 length(开区间思想)
  4. 找左边界时 if (nums[mid] < target) left = mid+1 else right = mid
    → 不要写成 <=,否则会错
  5. 旋转数组怎么判断哪边有序?
    → 看 nums[mid] 和 nums[right] 的关系
  6. 二分答案时,check 函数写错方向最常见
    → 记住:能行 → 尝试更小;不行 → 尝试更大

5. 练习建议

  • 先把 704、35、34 三题手写 10 遍(不同写法)
  • 然后做 33、153、875 这三道经典变形
  • 每天做 2-3 道二分题,坚持 2 周
  • 强烈推荐看 labuladong 的《二分查找详解》系列文章(非常系统)

有哪一道题想看详细题解或代码,或者想针对某个变体(旋转、答二分、峰值、二维)深入练习,告诉我,我可以给你单独出题或解析!加油刷题!

文章已创建 4401

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部