二分查找总结

本文详细介绍了二分查找算法,包括寻找目标值、左侧边界和右侧边界的实现。通过实例展示了如何使用二分查找提高搜索效率,从暴力遍历的线性时间复杂度提升到对数时间复杂度。同时,强调了在处理边界条件时的注意事项。

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

二分查找

二分查找是一种我们在初中就学过的效率较高的用对数级别的时间复杂度进行遍历的算法,关于这个算法,有很多细节的地方需要注意,参考labuladong老师的《算法小抄》 现总结如下:
1:找目标值的二分查找
例如:

nums=[1,2,3,4,5,6,7];
target=3;

求:target的索引值。
那么这个问题,有两个方法,1:暴力遍历,时间复杂度是O(n)

for(int i=0;i<nums.size();i++)
{
	if(nums[i]==target)
	{
		return i;
	}
}

上述代码的逻辑非常简单。显然,根据我们初中学过的二分查找,可以更快,时间复杂度更低(logN)级别的。
我将代码及其逻辑梳理如下

int binarysearch(vector<int> nums,int target)
{	if(nums.size()==0) return -1;
	int left=0;
	int right=nums.size()-1;//从这里的定义我们可以看到,右边的指针指向数组元素的最后一个元素;
	while(left<=right)//因为搜索区间是一个[a,b]左闭右闭的区间,所以终止条件是[right+1, right],这样的一个区间是没有元素的,然而如果写成(left<right),那这种情况下mid就是这俩索引中其中的一个值,就会漏掉另外一个;
	{
		int mid=left+(right-left)/2;//这种写法可以有效的防止溢出;
		if(nums[mid]==target)
		{	
			return mid;
		}
		else if(nums[mid]<target)
		{
			left=mid+1;//如果nums[mid]<target,那么应该在[mid+1,right]的区间中接着找
		}
		else if(nums[mid]>target)
		{
			right=mid-1;//如果nums[mid]>target,那么应该在[left,mid-1]中接着找
		}	
	}
	return -1;
}

第二种情况是寻找左侧边界的二分查找算法;

int left_bound_binarysearch(vector<int> nums,int  target)
{
	if(nums.size()==0) return -1;
	int left=0;
	int right=nums.size()-1;
	while(left<=right)
	{
		int mid=left+(right-left)/2;
		if(nums[mid]<target)
		{
			left=mid+1;
		}
		else if(nums[mid]==target)
		{
			right=mid-1;//关键在于这一步,如果找到了这个元素,不立马返回这个元素,而是向左缩小右侧边界,
		}
		else if(nums[mid]>target)
		{
			right=mid-1;
		}
	}
	//由于退出while的条件是left=right+1;因此当target>数组中的所有元素时,left会越界,那么这种情况下需要检查越界情况
	if(left>=nums.size()||nums[left]!=target)//由于在相等的情况下,right=mid-1,然后就是一直移动左边的指针,直到left=right+1,这种情况下,left一定会移动到target的位置,如果不是target的位置,那一定是溢出边界了;
	{
		return -1;
	}
	return left;
}

同理寻找右侧边界的代码也很简单

int right_bound_binarysearch(vector<int> nums,int  target)
{
	if(nums.size()==0) return -1;
	int left=0;
	int right=nums.size()-1;
	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-1;
		}
	}
	//由于退出while的条件是left=right+1;因此当target<数组中的所有元素时,right会越界,那么这种情况下需要检查越界情况
	if(right<0||nums[right]!=target)//这里同上述左侧检查边界情况一样,一直向右缩小左边界,当左边界==target时,这时left的操作是left=mid+1,然后一直缩小右边界,直到left=right+1时结束,如果右边界<0,或者nums[right]!=target,那一定是出界了;
	{
		return -1;
	}
	return right;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值