【从零开始】二分法的妙用

本文从零开始介绍二分查找,详细探讨了二分查找的细节,包括左闭右开和左闭右闭的区别,以及在不同情况下的区间选择。文章通过分析LeetCode题目,如二分查找、搜索插入位置、平方根求解等,巩固了二分法的理解,并进一步讨论了在旋转数组和存在重复元素时如何应用二分查找。
摘要由CSDN通过智能技术生成

写在前面

从零开始的刷题之旅,首先是最基础的数组。

而在数组中,二分查找是一个非常常见的问题

除了我们常见的需要找到某一数之外,还有一些变体比如寻找边界,数组旋转等等。这次就将他们一网打尽。

首先根据一道题来摸清楚二分查找最基础的框架

leetcode 704 二分查找

这样的基础框架是很好写的,只是需要注意细节。

int search(vector<int>& nums,int target){

	int left=0;
	int right=nums.size()-1;

	while(left<=right){

		int middle = (left+right)/2;\
		
		if(nums[middle]>target){
			right=middle-1;
		}

		else if(nums[middle]<target){
			left=middle+1;
		}
		else//nums[middle]==target
		{
			return middle;	
		}

		
	}

	return -1;
}

这就是一个二分查找的基本框架。但是有些细节需要明确。

问题讨论

根据上面的框架,有这么几个问题需要明确:

左闭右开or左闭右闭

可以看到我们的left是0,right是nums.size()-1,也就对应着数组的第一个元素和最后一个元素。

这样的区间就是左闭右闭的,即[left,right]

我们也可以写为左闭右开的,即[left,right),那么right就是nums.size()

这两种写法有什么区别呢?区别在于while里的内容。

如果是左闭右闭,那么while的条件是left<=right,因为right是存在的,所以在两者相等时[left,right]也是有效的。(当然对于这道题来说,由于是升序序列所以不存在相等)

如果是左闭右开,那么while的条件是left<right,当left=right的时候这个区间就没有意义了,所以退出循环。

while中“=”的影响

知道什么时候加等于什么时候不加之后,我们来看循环内的代码。

  • middle在left和right的中间,需要注意一般写为left + ((right - left) / 2) 防止溢出。
  • 如果middle正好是我们要找的target,那么直接返回即可。
  • 如果要找的target在middle的左边,那么我们理所当然要缩小右边界,缩到middle这里
    • 如果是左闭右闭,那么我们的缩小区间应该是[left,middle-1],所以right=middle-1
    • 如果是左闭右开,那么我们的缩小区间应该是[left,middle),所以right=middle
  • 如果要找的target在middle的右边,那么我们理所当然要缩小左边界,缩到middle这里
    • 如果是左闭右闭,那么我们的缩小区间应该是[middle+1,right],所以left=middle+1
    • 如果是左闭右开,那么我们的缩小区间应该是[middle+1,right),所以left=middle+1

所以到这里我们也应该会写第二种左闭右开的写法了:

int search(vector<int>& nums,int target){

	int left=0;
	int right=nums.size();

	while(left<right){

		in
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值