二分查找:左右边界

文章目录

一、把问题拆成两次边界搜索

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

左边界是第一个等于 target 的位置,右边界是最后一个等于 target 的位置。使用闭区间 [left, right] 搜索时,需要先确定区间外已经知道什么,再决定 mid 是否仍可能是答案。

搜索目标 left 左侧 right 右侧
左边界 < target >= target
右边界 <= target > target

表格描述的是候选区间外侧,不包含仍待判断的 [left, right]。

二、寻找左边界

左边界搜索使用下中点:

text 复制代码
mid = left + (right - left) / 2
  • 当 nums[mid] < target 时,mid 及其左侧不可能是答案,令 left = mid + 1。
  • 当 nums[mid] >= target 时,mid 仍可能是第一个目标值,令 right = mid 保留它。

当区间只剩 [i, i + 1] 时,下中点为 i。无论更新 left = mid + 1 还是 right = mid,区间都会继续缩小。

三、寻找右边界

右边界搜索使用上中点:

text 复制代码
mid = left + (right - left) / 2 + 1
  • 当 nums[mid] <= target 时,mid 仍可能是最后一个目标值,令 left = mid 保留它。
  • 当 nums[mid] > target 时,mid 及其右侧不可能是答案,令 right = mid - 1。

如果这里仍使用下中点,那么在 [i, i + 1] 中会得到 mid == left == i。一旦进入 left = mid 分支,区间不会变化,从而产生死循环。改用上中点后,mid == i + 1,两个分支都能让区间收缩。

四、目标不存在时的校验

这两次搜索都会返回数组中的一个候选下标,但候选值不一定等于 target。例如数组只有 [5] 时,查找 4 或 6 都会得到候选位置 0,因此不能只用"左候选是否大于右候选"判断目标是否存在。

完整代码需要额外处理空数组,并检查两个候选位置的值:

java 复制代码
class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] ret = new int[2];
        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;
            }
        }
        ret[0] = left;

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

        if (nums.length == 0
                || nums[ret[0]] != target
                || nums[ret[1]] != target) {
            ret[0] = -1;
            ret[1] = -1;
        }
        return ret;
    }
}

两次二分搜索的时间复杂度均为 O(log n),总时间复杂度仍为 O(log n);除返回数组外,额外空间复杂度为 O(1)。

相关推荐
强哥聊算力4 小时前
《算力江湖·英伟达传奇》第七集:ChatGPT出现前夜,英伟达发生了什么?
服务器·人工智能·算法·ai·chatgpt·gpu算力
Navigator_Z8 小时前
LeetCode //C - 1289. Minimum Falling Path Sum II
c语言·算法·leetcode
CCblandy8 小时前
令牌桶在 0.9 倍负载超发 19%、固定窗口边界放行 20 个:四种限流算法同构实测
后端·python·算法·性能优化·架构
mmmmath_39 小时前
LeetCode.104.二叉树的最大深度
数据结构·leetcode
YangYang9YangYan10 小时前
2027供应链计划校招:数学与应用数学专业如何把预测模型讲成业务决策?
人工智能·sql·算法
jsjzsl210 小时前
递归自改进系统(RSI)的本质是自发对称破缺:智能爆炸有界—— AI研发切记盲目投入
人工智能·python·算法
程序员清风10 小时前
最短路径算法:BFS、Dijkstra 与 Floyd
java·算法·宽度优先
梦帮科技10 小时前
Kali Linux Scapy 畸形报文构造学——深度解剖非法 TCP Flags 与反常序列号
linux·爬虫·神经网络·算法·数学建模·系统架构·模拟退火算法
171320330计算机毕设编程11 小时前
计算机毕业设计 基于YOLO改进算法的车辆特征识别系统设计与实现--lw
java·大数据·python·sql·算法