【Leetcode每日一题】35.搜素插入位置|二分查找数组下标

在这里插入图片描述

🌱博主简介:大一计科生,努力学习Java中!热爱写博客~预备程序媛
📜所属专栏:LeetCode每日一题–进击大厂
✈往期博文回顾: 【JavaSE】保姆级教程|1万字+10张图学会类与对象–建议收藏
🕵️‍♂️近期目标:成为千粉小博主。
🌺“再牛的程序员也是从小白开始,既然开始了,就全身心投入去学习技术”

题目描述

35. 搜索插入位置
在这里插入图片描述

解题思路

  • 题型:数组、二分查找(变式)—寻找第1个大于等于目标值的元素

  • 关键:二分查找的关键点就是—两边夹(高数上又叫作夹逼准则)。left和right确定答案所在区间,通过mid(把区间划分为[left,mid]&[mid+1,right]两个区间)来缩小区间范围,直到left==right,即获得答案。

    • 为什么呢?存在如下定理:A <= target <= B,当A = B时,target = A = B
  • 思路
    1.确定答案可能取值区间[left,right]
    2.left = 0;right = array.length;
    (因为此题中array.length也有可能为答案)
    3.while(left<right)(不考虑所谓的什么闭区间,就仅仅代表它本身的含义:当left==right时,即找到答案,跳出循环

    • 为什么呢?因为很多问题就这么设计,一定要等到最后才能确定问题的答案,在很多时候,不能在循环体中找到答案。

    4.确定循环体中分支的两种情况:

    • a.target>array[mid]:left=mid+1
    • b.else (即target<=array[mid]):right=mid

    5.left==right跳出循环体后:return right
    🌟为什么呢直接return left/right呢?我们来分析一下跳出循环后的两种情况

    • 情况1:最简单的一种情况,即夹逼准则成立时,找到答案:array[left]=array[right]=targer,这个很好理解。此时array[left]==targert
    • 情况2:即没找到与target相等的元素的下标。因为array[left]<=target<=array[right]是默认恒成立的–即target应该存在于这个区间。即left指针指向[left,right]最后一个小于等于target的元素right指针指向[left,right]第一个大于等于target的元素。在[left,right]实际区间范围不断缩小的过程中,当left和right重合时,right指向的是[0,array.length-1]这个区间第一个大于等于target的元素.(我个人目前觉得在理解层面上,return right比return left要好理解一些,虽然两者达到的效果是一样的)

2023:1:24日补充图解:
在这里插入图片描述

代码实现–Java

class Solution {
    public int searchInsert(int[] nums, int target) {
         int left=0,right=nums.length;//因为nums.length可能为答案
         while (left<right){
            int mid=left+(right-left)/2;//防止溢出(但其实left和right表示数组小标没什么必要)
            if(target>nums[mid]){
                left=mid+1;//下一次搜索区间为[mid+1,right]
            }
            else{
                right=mid;//下一次搜素区间为[left,mid]
            }
        }
        return right;
    }
}

总结&易错

  • 【易错】二分查找的重点就划分区间、逐渐缩小、两边夹,关于划分区间这题我用的划分为[left,mid]和[mid+1,right],为什么不是[left,mid-1]和[mid,right]呢?—因为会出现死循环
//下面是把区间划分为[left,mid-1]和[mid,right]的情况(错误代码)
class Solution {
    public int searchInsert(int[] nums, int target) {
         int left=0,right=nums.length;//因为nums.length可能为答案
         while (left<right){
            int mid=left+(right-left)/2;//防止溢出(但其实left和right表示数组小标没什么必要)
            if(target<nums[mid]){
                right=mid-1;//下一次搜索区间为[left,mid-1]
            }
            else{
                left=mid;//下一次搜素区间为[mid,right]
            }
        }
        return right;
    }
}

死循环分析:
输入[1,3,5,6] 2出现超时。分析:
第一次循环:mid=2;区间被分为[0,1],[2…4],下一次搜索区间为[0,1],left:0,right:1
第二次循环:mid=0,left:0,right:1,下次循环区间还是[0,1]
第三次循环:mid=0,left:0,right:1,下次循环区间还是[0,1]
…死循环

  • 解决方法:把(left+right)/2修改为(left+right+1)/2
    • 其实本质死循环的原因是只有两个元素时,mid指针指向的是前一个元素,再mid=(left+right)/2,不能把区间[left,mid-1]和[mid,right]其缩小,所以才会发生死循环。通过修改为mid=(left+right+1)/2,此时可以缩小区间,即不会发生死循环。

在这里插入图片描述

  • 【重点】二分法的关键是缩小区间,死循环发生的原因是某次循环没有缩小区间导致二分失败。

  • 【重点】此题right设置为array.length的原因是array.length也有可能是问题答案

  • 【重点】二分查找的判断条件写成while(left<right),代表的是搜索区间为[left,right],一旦left==right,即此时找到问题答案,立即跳出循环。

  • 【重点】循环不变量:在[left,right]搜索答案


👩‍🎨write in the end:

  • 🙇‍♀️建立此专栏的初衷是为了监督自己每天认真刷一个题,积少成多。并把自己每次刷题的思路、收获以博文的形式分享出来,帮助更多人,以及方便后续复习。如果有兴趣的同学可以订阅此专栏,我们一起刷题,一起交流,进步和学习!专栏:LeetCode每日一题–进击大厂

在这里插入图片描述

  • 42
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 67
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是瑶瑶子啦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值