关于二分查找(Binary Search)算法的几个细节问题

2020年8月7日 周五 天气晴 【不悲叹过去,不荒废现在,不惧怕未来】


最近一直在LeetCode上刷二分查找相关的题,发现有几点细节问题需要注意,特地总结如下:

(1)之所以将 mid = (left + right) / 2 写成 mid = left + (right - left) / 2,是怕 left + right 会整型溢出

(2)除以2没必要写成 >> 1,写成 /2 就行,因为编译器会自动把 /2 优化成 >> 1,写成左移的形式反而会降低代码的可读性。

(3)如果在二分查找问题中遇到要返回数组下标,并且这个下标可能会越界(比如插入数据到数组尾部,返回的下标就是越界的),这时候可以考虑将左边界 r 改成数组的长度 len ,而不是 len - 1

(4)二分查找代码的写法不唯一,选择一种自己喜欢的就好,下面附上我自己常用的写法:

// 返回的是 是否存在target 这么一个数
int BinarySearch(vector<int>& nums, int target) {
    int l = 0, r = nums.size()-1;
    while (l <= r) {
        int m = (r + l) / 2;
        if (nums[m] == target) 
            return m;
        else if(nums[m] < target) 
            l = m + 1;
        else 
            r = m - 1;
    }
    return -1;
}

二分查找有很多变形,比如查找第一个(最后一个)大于(小于或等于)指定元素的位置,都是根据上面的代码改动而来,因此最基本的要牢记,需要变形的时候简单修改一下就可以了。


2021年02月02日 周二

今天在做二分查找变形题目的时候,才发现细节是魔鬼,并不是我之前说的“简单修改一下就可以了”,所以这里还是记录一下关于二分查找的变形,题目可参考剑指 Offer 53 - I. 在排序数组中查找数字 I(二分查找变形,也就是手撸 lower_bound()、upper_bound())

手撸 lower_bound()、upper_bound() 代码如下:

// 返回 第一个大于或等于target 的元素位置(lower_bound())
int my_lower_bound(vector<int>& nums, int target) {
	int l = 0, r = nums.size() - 1;
	while (l < r) {
		int m = l + (r - l) / 2;
		if (nums[m] < target) l = m + 1;
		else if (nums[m] == target) r = m;
		else r = m - 1;
	}
	// 细节:l == r 的情况单独判断,不容易出错
	return nums[l] < target ? -1 : l;
}

// 返回 第一个大于target 的元素位置(upper_bound())
int my_upper_bound(vector<int>& nums, int target) {
	int l = 0, r = nums.size() - 1;
	while (l < r) {
		int m = l + (r - l) / 2;
		if (nums[m] < target) l = m + 1;
		else if (nums[m] == target) l = m + 1;
		else r = m;
	}
	// 细节:l == r 的情况单独判断,不容易出错
	return nums[l] <= target ? -1 : l;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值