一个较为通用的二分解法模板

虽然说是一个较为通用的二分解法,但目前我是觉得这种对二分题的思维方式挺好的,之后的一些类型题其实大多是这个较为通用的二分解法模板上加一些特判。

其实有很多想说的,但说真的,自己明白了,想表达让别人明白真的挺难的。

这里介绍两道leekcode题,虽然都是简单题,但我也是从中激发出灵感的。

先归类下简单二分题,其实个人认为就两种,一种是目标在原数组,一种是目标不在原数组,要求找比较近的下标。

第一种类型先不说了,因为第二种会了,你第一种也是一样套模板。

先说下模板吧

vector<int>arr

int left,right

while(left<=right)

{

        int mid=left+(right-left)/2;

        if(arr[left]???arr[mid])

        {        

                left=mid+1;

        }

        else

        {

                right=mid-1;

        }

}

return ???;

                                                是不是现在内心想说,就这吗。。。

emm,确实哈。但是你真的理解吗

先看下新手比较喜欢的,包括之前的我哈

                这种解法,emm其实做题越多,你发现这种方法是可以解决问题,但模板可能变来变去,很容易刷了很久题还是老样子,感觉就跟我们高中写作一样哈(勾起了不好的回忆)

                                这里也不过多解释这种二分。直接康康模板怎么写

                                        特判大家可以不管(也好理解)。这就开始逐句分析

1:while(l<=r)很重要待会说

2:mid跳过

3:第一个if,问下大家,在nums[mid]<target的情况下,让l=mid+1;这时候l可能越过答案吗,答案是绝对不可能(这个不解释了,很简单的逻辑)。那好,既然如此,也就是说无论经过多少次while循环,答案的位置下标总是>=l的,换句话说到while结束,l依旧是满足nums[l]<=target,而此时已经走完了数组,也就是说l就是答案了。(感觉这样说有点迷糊,但大家可以自己细心想想,也可以这么理解,l在这样的循环里总是满足nums[l]<target,那走完整个数组,l自然是答案

4:else里是r=mid-1,emm,先说下结论,跟第一点结合下,只要是while(l<=r)的话,一定既要l=mid+1,r也要r=mid-1,不然会有机会出现死循环。

        emm,但你可能会说,如果r也按照第3点的思维的话,r是可能越过答案的,也就是r可能在左边,答案在右边,对,没错,但是如果这样答案下标就一定是在r+1上,怎么说的呢。。emm其实也是很简单的逻辑,else里条件这里是nums[mid]>=target,我们拆分下,如果是nums[mid]>target的时候让r=mid-1,那r也绝对不会跨过答案,但是如果是==的情况,那自然就跨过了,而且也就是r=答案下标-1;。。emm你说如果r都跨过答案,那不就完了吗啊,。。肯定不是拉,这也就是为什么我们要while(l<=r),当r跨过答案后,l就会一直向右移动到l==r,这时候又因为答案下标==r+1,就依旧是进入到第一个if,也就这样得到了答案。

        

        感觉说了很多废话,也没说什么套路,这里就总结下,也就是我们的模板要变的就只有  if(arr[left]???arr[mid])中的符号

      

        那到底怎么变呢,我们先说下就是必须让l和r中的其中一个一定不跨过答案(可等于答案,e,这不是废话吗,不等于答案,我咋返回啊),一个一定跨过答案即可,上面的例子,就是l一定不跨过答案,r一定跨过答案,你可能会上上面r可能不跨过答案啊,emm,其实是一定的,就算l先到达了答案,最后l==r的时候,r还是会r=mid-1跨过答案来结束循环。

        总结换句话说,也就是通过改变if(arr[left]???arr[mid])中的符号,你必须让l和r中的其中一个一定不跨过答案(可等于答案,e,这不是废话吗,不等于答案,我咋返回啊),一个一定跨过答案即可

        然后返回值自然就是不跨过答案的那一个,本题就是l,所以就是return l;

        好了,再水水字数,再举个简单题,举个return r;带大家彻底理解这个模板

                                                                先看看模板答案

 怎么说,我先说题目的结论吧,先不让大家分析题目了。(大家自己私下自己分析题目逻辑)

1:在middle*middle<=x的情况下,让left=middle+1;可能会跨过答案(这里我严谨点,换句话说,最后一定会跨过答案,而单论具体一次可能不跨过。。这不是教语文了吗。。)

2:else里具体就是当middle*middle>x的情况下,让right=middle-1;right是一定不会跨过答案的

(换句话说,最后while循环结束,整个数组都走完一边,right就一定是答案)。

3:哎,还是再提一下吧,为什么left跨过了答案,right最后还是可以找到答案。如果left此时跨过了答案,一定是答案下标=left-1;这时候因为left都已经跨过了答案,那么left到right之间的都不符合要求,right下标就一直向右直到left==right,这时候又因为left也不是答案,答案下标是left-1,那么这次循环自然也就是进入else里面,让right=mid-1,因为right是一定不会跨过答案的

4:最后return right;emm,看到1,2点应该也明白

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值