【无标题】

二分算法

核心原理

二分算法(Binary Search),又称折半查找,是一种高效的查找算法,用于在有序集合中快速定位目标元素。其核心思想是"每次通过与中间元素比较,将查找范围缩小一半",从而实现对数级的时间复杂度

核心逻辑

  1. 确定边界:定义查找范围的左边界(left)和右边界(right),初始时左边界为集合起始索引(通常是0),右边界为集合末尾索引(通常是length-1)。

  2. 计算中点:计算当前范围的中间索引mid = left + (right - left) // 2(用这种方式而非(left+right)//2,是为了避免left和right过大时出现整数溢出)。

  3. 比较判断

    若目标值 == 中间元素(nums[mid]):找到目标,返回mid。

  4. 若目标值 < 中间元素:目标在左半部分,将右边界更新为mid - 1。

  5. 若目标值 > 中间元素:目标在右半部分,将左边界更新为mid + 1。

  6. 循环终止:重复步骤2-3,直到左边界 > 右边界,此时说明集合中无目标元素,返回-1或其他标识。

关键特性

  • 时间复杂度:O(log n),n为集合元素个数,每轮查找范围减半,效率远高于线性查找(O(n))。

  • 空间复杂度:递归实现为O(log n)(栈空间),迭代实现为O(1)(仅用几个变量)。

  • 适用前提:必须是有序集合(升序或降序,需统一判断逻辑),且集合支持随机访问(如数组,链表不适用,因无法快速定位mid)

实战

问题

给定升序数组nums和目标值target,若数组中有多个target,返回第一个出现的索引;若不存在,返回-1

思路

当nums[mid] == target时,不直接返回,而是将右边界收缩到mid(而非mid-1),继续向左查找,直到左边界>右边界,最终判断左边界是否为目标值。

实现

java 复制代码
import java.util.Arrays;

public class FindLeftBoundDemo {
    // 查找目标值的左边界(第一个等于target的元素)
    public static int findLeftBound(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) {
                right = mid - 1;  // 不返回,继续向左找更左的边界
            } else if (nums[mid] < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        // 循环结束后,left可能是左边界,也可能不存在
        if (left < nums.length && nums[left] == target) {
            return left;
        }
        return -1;
    }

    // 测试案例
    public static void main(String[] args) {
        int[] nums = {1, 2, 2, 2, 3, 4};
        int target = 2;
        System.out.println(findLeftBound(nums, target));  // 输出:1(第一个2的索引)

        int target2 = 5;
        System.out.println(findLeftBound(nums, target2));  // 输出:-1
    }
}

注意事项

  1. 边界条件处理

    循环条件用left <= right还是left <?取决于是否要"包含边界元素"。若用left <,右边界初始需设为len(nums)(而非len(nums)-1),适用于"找插入位置"等场景。

  2. 避免数组越界:判断结果时需检查left是否在数组范围内(如左边界查找时的left < len(nums))。

  3. 中点计算 :必须用mid = left + (right - left) // 2,而非(left + right) // 2。例如left=231-1、right=231-1时,left+right会超出Python整数范围(虽Python支持大数,但其他语言如Java会溢出)。

  4. 有序性保证:若数组无序,必须先排序(但排序会消耗O(n log n)时间,若仅查找一次,不如直接线性查找;若多次查找,排序+二分更高效)。

  5. 重复元素处理:普通二分可能返回任意一个重复元素的索引,需通过"边界查找"逻辑定位第一个或最后一个。

相关推荐
NAGNIP8 小时前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
程序员清风15 小时前
程序员兼职必看:靠谱软件外包平台挑选指南与避坑清单!
java·后端·面试
皮皮林55116 小时前
利用闲置 Mac 从零部署 OpenClaw 教程 !
java
颜酱17 小时前
单调栈:从模板到实战
javascript·后端·算法
CoovallyAIHub20 小时前
仿生学突破:SILD模型如何让无人机在电力线迷宫中发现“隐形威胁”
深度学习·算法·计算机视觉
CoovallyAIHub20 小时前
从春晚机器人到零样本革命:YOLO26-Pose姿态估计实战指南
深度学习·算法·计算机视觉
CoovallyAIHub20 小时前
Le-DETR:省80%预训练数据,这个实时检测Transformer刷新SOTA|Georgia Tech & 北交大
深度学习·算法·计算机视觉
CoovallyAIHub20 小时前
强化学习凭什么比监督学习更聪明?RL的“聪明”并非来自算法,而是因为它学会了“挑食”
深度学习·算法·计算机视觉
CoovallyAIHub21 小时前
YOLO-IOD深度解析:打破实时增量目标检测的三重知识冲突
深度学习·算法·计算机视觉
华仔啊21 小时前
挖到了 1 个 Java 小特性:var,用完就回不去了
java·后端