二分查找算法学习及示例

参考链接:leetcode二分查找总结(模板+练习)

题一(278. 第一个错误的版本)

第一天写力扣给了这个题,T-T有被自己菜瞎《第一个错误版本
在这里插入图片描述

思路1

第一次思路错误,想的是与快速排序相似的

//首先测试二分的那个
//如果运行错误的话,向前运行二分的那个
//递归该函数
//如果运行正确的话,向后运行二分的那个
//跳出条件想不出来了呜呜

这个思路错误的原因是:找不到出口

错误1

这个思路错误的原因是:当输入n= 0、1 时,while循环进不去怎么办?只能输出mid。
事实上这时候输出left就可以了。但是我又进入了错误二:

public class Solution extends VersionControl {
    public int firstBadVersion(int n) {
        //用mid来记录跳出条件
        int left=1;
        int right=n;
        int mid=0;

        while(left<right){
            mid =(left+right)/2;
            //如果中间正确的话,向后运行
            if(!isBadVersion(mid)){
                left=mid+1;
            }
            else{//如果中间错误的话,向前运行
                right=mid;
            }
        }
        return mid;
    }
}

错误2

我以为,只要输出让mid等于边界就行了。那这样就真的对了吗??
错误一是左边界的问题还是右边界的问题?

这里可以结合一下盒子模型理解一下边界的问题。
数量为n的内部有一个错误。

  • 可以想象成这样的二维情况下的盒子模型
    在这里插入图片描述

边界是否被完全规避?!

如果像错误二中这样更改是处理了右间隔,并没有处理左间隔。

(什么时候处理了左右边界?left和right的时候就处理了)

public class Solution extends VersionControl {
    public int firstBadVersion(int n) {
        //用mid来记录跳出条件
        int left=1;
        int right=n;
        int mid=(left+right)/2;

        while(left<right){
            mid =(left+right)/2;
            //如果中间正确的话,向后运行
            if(!isBadVersion(mid)){
                left=mid+1;
            }
            else{//如果中间错误的话,向前运行
                right=mid;
            }
        }
        return mid;
    }
}

错误3

在错误3中的更改中处理了左间隔,正常来说这是完全正确的版本。

public class Solution extends VersionControl {
    public int firstBadVersion(int n) {
        //用mid来记录跳出条件
        int left=1;
        int right=n;
        int mid=0;

        while(left<right){
            mid =(left+right)/2;
            //如果中间正确的话,向后运行
            if(!isBadVersion(mid)){
                left=mid+1;
            }
            else{//如果中间错误的话,向前运行
                right=mid;
            }
        }
        return left;
    }
}

错误4

错误:mid = left + (right - left) / 2 ;
而不是mid =(left+right)/ 2
第三种写法会出现数组溢出的问题。left + right过大的情况下数字会超大,(2倍增大了)

  • 尽量先做减法后做加法
public class Solution extends VersionControl {
    public int firstBadVersion(int n) {
        //用mid来记录跳出条件
        int left=1;
        int right=n;
        // int mid=(left+right)/2;
        int mid = 0; // 防止计算时溢出
        while(left<right){
            mid = left + (right - left) / 2;
            //如果中间正确的话,向后运行
            if(!isBadVersion(mid)){
                left=mid+1;
            }
            else{//如果中间错误的话,向前运行
                right=mid;
            }
        }
        return left;
    }
}

边界值模板

class Solution {
    public int searchInsert(int[] nums, int target) {
        int left = 0, right = nums.length - 1; // 注意
        while(left <= right) { // 注意
            int mid = (left + right) / 2; // 注意
            if(nums[mid] == target) { // 注意
                // 相关逻辑
            } else if(nums[mid] < target) {
                left = mid + 1; // 注意
            } else {
                right = mid - 1; // 注意
            }
        }
        // 相关返回值
        return 0;
    }
}

题二(35. 搜索插入位置)

35. 搜索插入位置
二分查找的另一道题,直接写出思路,困在边界值的处理上。

错误一

第一个版本太多边界值处理不清楚,感觉陷进去了,自己的逻辑一点也理不清。想通过if语句规避掉所有错误。

public static int searchInsert1(int[] nums, int target) {
    int left=0;
    int right=nums.length-1;
    int mid=0;
    while(left<right){
        mid=left+(right-left)/2;
        if(nums[mid]==target){
            return mid;
        }
        if(nums[mid]<target){
            left=mid+1;
        }else{
            right=mid;
        }
    }

    if(nums.length==1&&nums[left]<target){
        return 1;
    }

    if (left==nums.length-1){
        return nums.length;
    }

    return left;
}

错误二

参照边界值模板直接写出第一个版本

public static int searchInsert(int[] nums, int target) {
    int left = 0, right = nums.length - 1; // 注意
    while(left <= right) { // 注意
        int mid = (left + right) / 2; // 注意
        if(nums[mid] == target) { // 注意
            // 相关逻辑
            return left;
        } else if(nums[mid] < target) {
            left = mid + 1; // 注意
        } else {
            right = mid - 1; // 注意
        }
    }
    // 相关返回值
    return left;
}

错误三

当nums[mid] == target时应直接返回mid

public static int searchInsert(int[] nums, int target) {
    int left = 0, right = nums.length - 1; // 注意
    while(left <= right) { // 注意
        int mid = (left + right) / 2; // 注意
        if(nums[mid] == target) { // 注意
            // 相关逻辑
            return mid;
        } else if(nums[mid] < target) {
            left = mid + 1; // 注意
        } else {
            right = mid - 1; // 注意
        }
    }
    // 相关返回值
    return left;
}

学会自己编写测试数据

要学会自己编写测试数据

  1. [1] 0
  2. [1] 2
  3. [1234] 1、3、4
  4. [123] 1、2、3
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值