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

勤奋不是嘴上说说而已,而是实际的行动,在勤奋的苦度中持之以恒,永不退却。业精于勤,荒于嬉;行成于思,毁于随。在人生的仕途上,我们毫不迟疑地选择勤奋,她是几乎于世界上一切成就的催产婆。只要我们拥着勤奋去思考,拥着勤奋的手去耕耘,用抱勤奋的心去对待工作,浪迹红尘而坚韧不拔,那么,我们的生命就会绽放火花,让人生的时光更加的闪亮而精彩。

导读:本篇文章讲解 【Leetcode每日一题】35.搜素插入位置|二分查找数组下标,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

在这里插入图片描述

🌱博主简介:大一计科生,努力学习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每日一题–进击大厂

在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/142458.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!