【LeetCode】【数组】【二分查找总结】

本文详细解析了二分查找的基本、左边界和右边界三种情况,对比了循环条件和边界调整策略,展示了如何根据目标查找不同位置的逻辑变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考
细节详解
二分查找
相关问题
704.二分查找
34.在排序数组中查找元素的第一个和最后一个位置

  • 875.爱吃香蕉的珂珂
  • 1011 .在 D 天内送达包裹的能力

二分查找-basic

时间复杂度 :O(logn);
要求:排序数组。

1. caution:

循环不变量的定义 :// 在nums[l…r]之中查找target
循环继续条件: l <= r ,因为循环不变量定义了是闭区间,所以要加上等号,使得相等的时候还继续循环,不会漏掉l==r时那个数。

template<typename T>
int binarySearch(T nums[], T target) {
    int left = 0; 
    int right = nums.size() - 1; // 注意

    while(left <= right) {
        int mid = left + (right - left) / 2;
        if(nums[mid] == target)
            return mid; 
        else if (nums[mid] < target)
            left = mid + 1; // 注意
        else if (nums[mid] > target)
            right = mid - 1; // 注意
    }
    return -1;
}

二分查找-左边界

1. caution:

循环不变量的定义 :// 在nums[l…r)之中查找target的左边界
循环继续条件: l < r ,因为循环不变量定义了是开区间,所以不用加上等号,使得相等的时候break。

template<typename T>
int binarySearch(T nums[], T target) {
    int left = 0; 
    int right = nums.size() ; // 注意
	if (nums.size() == 0 || nums[left]>target) return -1;//排除不在范围内的target
	
    while(left < right) {// 注意
        int mid = left + (right - left) / 2;
        if(nums[mid] == target)
            right = mid; // 缩小右边界
        else if (nums[mid] < target)
            left = mid + 1; // 注意
        else if (nums[mid] > target)
            right = mid; // 因为是开区间,不需要mid-1
    }
	// target 比所有数都大
	if (left == nums.length) return -1;
	// 类似之前算法的处理方式
	return nums[left] == target ? left : -1;
}

二分查找-右边界

1. caution:

循环不变量的定义 :// 在nums[l…r)之中查找右边界
循环继续条件: l < r ,因为循环不变量定义了是开区间,所以不用加上等号,使得相等的时候break。
因为r=n,l=mid+1,所以最后的时候lrmid+1,所以return r-1。

template<typename T>
int binarySearch(T nums[], T target) {
    int left = 0; 
    int right = nums.size(); // 注意
    if (nums.size() == 0 || nums[right-1]<target) return -1;//排除不在范围内的target

    while(left < right) {
        int mid = left + (right - left) / 2;
        if(nums[mid] == target)
            left = mid + 1; //缩小左边界
        else if (nums[mid] < target)
            left = mid + 1; // 注意
        else if (nums[mid] > target)
            right = mid; // 注意
    }
    // 
	if (left == 0) return -1;
	// 类似之前算法的处理方式
	return nums[right-1 ] == target ? (right-1) : -1;//这里注意是right-1
}

逻辑统一

来梳理一下这些细节差异的因果逻辑:

第一个,最基本的二分查找算法:

因为我们初始化 right = nums.length - 1
所以决定了我们的「搜索区间」是 [left, right]
所以决定了 while (left <= right)
同时也决定了 left = mid+1 和 right = mid-1

因为我们只需找到一个 target 的索引即可
所以当 nums[mid] == target 时可以立即返回

第二个,寻找左侧边界的二分查找:

因为我们初始化 right = nums.length
所以决定了我们的「搜索区间」是 [left, right)
所以决定了 while (left < right)
同时也决定了 left = mid + 1 和 right = mid

因为我们需找到 target 的最左侧索引
所以当 nums[mid] == target 时不要立即返回
而要收紧右侧边界以锁定左侧边界

第三个,寻找右侧边界的二分查找:

因为我们初始化 right = nums.length
所以决定了我们的「搜索区间」是 [left, right)
所以决定了 while (left < right)
同时也决定了 left = mid + 1 和 right = mid

因为我们需找到 target 的最右侧索引
所以当 nums[mid] == target 时不要立即返回
而要收紧左侧边界以锁定右侧边界

又因为收紧左侧边界时必须 left = mid + 1
所以最后无论返回 left 还是 right,必须减一

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值