二分法的思路总结

1. 二分法的使用前提

1.数组是有序数组
2.数组的元素不重复,因为一旦又重复元素,使用二分法返回元素的下标可能不是唯一的
3.查找元素

2. 二分法的两种写法

第一种:左闭右闭[left,right]
1.int left =0; int right = nums.length-1;
2.while(left<=right) ,因为left==right是有意义的,所以要这么写
3. int mid = left+((right-left)/2);防止溢出,等同于(left+right)/2
4.当target < nums[mid]时,right = mid -1;当target >nums[mid],left=mid+1;

第二种:左闭右开 [ left,right )
1.int left =0; int right = nums.length;
2.while(left<right) ,这里使用<,因为left==right在区间 [ left,right )是没有意义的
3.int mid = left+((right-left)/2);防止溢出,等同于(left+right)/2
4.当target < nums[mid]时,right = mid ;当target >nums[mid],left=mid+1;

3.实例

3.1 二分查找
class Solution {
    /*
    *   1.左闭右闭 (<=)
         2.right=nums.length-1
         3.right = mid-1
         4.left = mid+1
    */
    public int search(int[] nums, int target) {
        int left =0;
        int right = nums.length-1;
        while(left<=right){
            int mid = left+((right-left)/2);//防止溢出,等同于(left+right)/2
            if(target < nums[mid]){
                right=mid-1;
            }
            else if(target>nums[mid]){
                left=mid+1;
            }else{
                return mid;//找到目标值,返回下标
            }
        }
        return -1;
    }
}
3.2 搜索插入位置

只需要在二分查找的基础上处理不在数组里的情况。即return left 或者 return right+1

搜索插入位置

class Solution {
    /*
    * 二分搜索:左闭右闭
    */
    public int searchInsert(int[] nums, int target) {
        int left = 0;
        int right = nums.length-1;
        
        while(left<=right){
            int mid =  left+((right-left)/2);
            if(target< nums[mid]){
                right=mid-1;
            }else if(target>nums[mid]){
                left=mid+1;
            }else{
                return mid;
            }
        }
        return right+1;//或者return left
    }
}
3.3在排序数组中查找元素的第一个和最后一个位置

这道题最大的不同在于数组中的元素,我们其他的不需要改动,只需要在找到mid时,以mid为基准,分别向左向右继续二分法寻找相等的值,然后存在数组里面输出即可。

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

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int left = 0;
        int right = nums.length-1;
        int[] res = {-1,-1};
        while(left<=right){
            int mid =left+((right-left)/2);
            if(target<nums[mid]){
                right=mid-1;
            }else if(target>nums[mid]){
                left=mid+1;
            }else{//找到一个目标值,我们还需要分别向左和向右找寻第二个目标值,这里无需返回·
                left=mid;
                right=mid;
                while(left>-1){//左边界
                    if(nums[left]!=target) break;//找不到符合条件的值,退出程序
                    res[0]=left;//将找到的值放在数组里
                    left--;
                }
                while(right<nums.length){//右边界
                    if(nums[right]!=target) break;
                    res[1]=right;
                    right++;
                }
                break;//退出else
            }
        }
        return res;
    }
}
3.4 开根

虽然是开根问题,但是也可以使用二分法。查找的边界是[0,x],需要满足的条件是mid*mid与x进行大小比较来确定下一个二分查找的范围。

开根号

class Solution {
    /*
    * 本题我们依然可以使用二分法查找,查找的边界是[0,x],需要满足的条件是mid*mid与x进行大小比较来确定下一个二分查找的范围。
    */
    public int mySqrt(int x) {
        int left =0;
        int right = x;
        int ans = 0;//用于输出答案

        while(left<=right){//内部不需要返回,找到最后的值
            int mid = left+((right-left)/2);
            
            if((long)mid*mid<=x){//因为我们要求得值包含在这个范围内,所以将<=写在一起
                ans=mid;
                left=mid+1;
            }
            else if((long)mid*mid>x){
                right=mid-1;
            }
        }
        return ans;
    }
}
3.5有效的完全平方数

用mid*mid和num比较来确定二分法下一步的区间

有效的完全平方数

class Solution {
    //二分法,用mid*mid和num比较来确定二分法下一步的区间
    public boolean isPerfectSquare(int num) {
        int left = 0;
        int right = num;
        while (left <= right) {
            int mid = (right - left) / 2 + left;
            long square = (long) mid * mid;
            if (square < num) {
                left = mid + 1;
            } else if (square > num) {
                right = mid - 1;
            } else {
                return true;
            }
        }
        return false;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值