二分思路整理

最近在刷二分。现在整理一下
二分看似简单,可是在处理边界情况下是真的难以琢磨,所以把稍微理解的记录一下,日后忘记可以快读回想。

模板

	while(l<=r){
	    int mid=l+((r-l)>>1);
	    if(nums[mid]==target)return mid;
	    if(nums[mid]<target)l=mid+1;
	    else r=mid-1;
	}

2.while(l<r)还是while(l<=r)
问题在于left == right的时候是否继续判断
一般来说,在搜索某个特定值的情况下,最后一个情况,我们还是要考虑的,所以,要写上等于号
但是,如果让我们返回最左边的一个数,或者右边一个数,
那么我们之间返回l或者r即可,使用while(L<R)(如果不理解可以往下看样例)

2.mid=l+r>>1 和 mid=l+((r-l)>>1);的区别,
没有区别,但是有可能会碰到l+r数值很大,溢出的情况,所以采用第二种方式

3.在有些情况下 r-l需要加1;有些时候不需要,
这个问题主要是在遇到死循环的情况下发生。
并且大多数发生在搜索左边极限或者右边极限的情况
比如在有时候写代码
这个问题我觉得可以从区间范围来思考
左闭右闭: [0, 5]
左开右开 (-1, 6),
左闭右开 [0 , 6)
左开右闭 (-1, 5],
在左闭右闭的情况下

4.mid有时候加减,有时间只加减一个。
这个问题如果在搜索某个固定值得情况下,mid加减一都需要,因为如果相等,那么就返回,不然的话就是不相等,那跳过这个数即可。
但是 在搜索左边极限或者右边极限的情况,需要判断是否相等,比如判断大于等于,那么mid往往不加一。(结合样例)

5.最后返回l还是r,
这个问题我总结不出来规律,每次都需要思考下,目前就是看求哪边的边界,就尽量返回哪边,(有懂的大佬恳请赐教)

搜索指定字符

LeetCode 374.猜数字大小

public class Solution extends GuessGame {
    public int guessNumber(int n) {
        int l=0,r=n;
        while(l<=r){
            int mid=l+((r-l)>>1);
            int s=guess(mid);
            if(s==0)return mid;
            if(s==-1)r=mid-1;
            else l=mid+1;
        }
        return 0;
    }
}

LeetCode 35. 搜索插入位置

class Solution {
    public int searchInsert(int[] nums, int target) {
        int l=0,r=nums.length-1;
        while(l<=r){
            int mid=l+((r-l)>>1);
            if(nums[mid]==target)return mid;
            if(nums[mid]>target)r=mid-1;
            else l=mid+1;
        }
        return l;
    }
}

题目要求返回插入位置,也就是寻找搜索中值后面的那个数,所以返回l;

搜索极限

LeetCode 34. 在排序数组中查找元素的第一个和最后一个位置

class Solution {
    public int[] searchRange(int[] nums, int target) {
        if(nums.length==0)return new int []{-1,-1};
        int l=0,r=nums.length-1;
        while(l<r){
            int mid=l+r>>1;
            if(nums[mid]>=target)r=mid;
            else l=mid+1;
        }
        if(nums[l]!=target)return new int []{-1,-1};
        int a=l;
        r=nums.length-1;
        while(l<r){
            int mid=l+r+1>>1;
            if(nums[mid]<=target)l=mid;
            else r=mid-1;
        }
        return new int []{a,r};
    }
}

这道题目要求找出极限问题,一般在求极限的时候,就要考虑mid加减1问题。
首先求出8在数组中的左极限,之后再求出右极限
这道题可以总结一个规律,
如果l往右寻找边界的时候,要l+r+1,否则不需要加一

LeetCode 69. x 的平方根

class Solution {
    public int mySqrt(int x) {
        if(x<2)return x;
        long l=1;
        long r=x/2;
        while(l<r){
            long mid=(l+r+1)>>1;
            if(mid * mid<=x)l=mid;
            else r=mid-1;
        }
        return (int)l;
    }
}

LeetCode 153. 寻找旋转排序数组中的最小值

假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
请找出其中最小的元素。
输入: [3,4,5,1,2]
输出: 1

首先 旋转了就有一个特性
旋转前半截都比第一个数大,后半截都比第一个数小。
那么说明,如果中值大于数组第一个数,最小值在右边
另外一种思路
如果中值大于右边的数,那么,最小值在右边。否则 最小值在左边

class Solution {
    public int findMin(int[] nums) {
        if(nums.length==0)return 0;
        int l=0,r=nums.length-1;
        while(l<r){
            int mid=l+r>>1;
            if(nums[mid]>nums[r])l=mid+1;
            else r=mid;
        }
        return nums[r];
    }
}

LeetCode 154. 寻找旋转排序数组中的最小值 II

如果有重复数字,那么需要特判一下是否不相等,因为相等的话就要左移

class Solution {
    public int findMin(int[] nums) {
        int l=0,r=nums.length-1;
        while(l<r){
            int mid= l+r>>1;
            if(nums[mid]>nums[r])l=mid+1;
            else if(nums[l]>nums[mid])r=mid;
            else r--;
        }
        return nums[r];
    }
}

未完待续。。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值