友友们好(^-^)🌹🌹🌹,我是杨枝,一枚在算法领域迈步的呆萌的博主呀~
目前还是一只纯纯的菜汪🐶。 典型的又菜又爱闹那种👀,做不好很多事,说不好很多话,写题还总不Ac😅,还在努力还在前进👣。
因为了,你们对我来说都是是独一无二的呀💓。在点开这篇文章的那一刻,我相信,我们之间相互需要彼此啦🌹🌹
时刻谨记:认真写算法,用心去分享。不负算法,不误卿。 感谢相遇(^㉨^)。
蓝桥杯的十种呼吸法是笔者结合自己的学习筛选出来的十个知识点。本着像看漫画一样了解算法原理。当日后自己确实遇到相关的习题了,可以再回头结合着我的题解报告来加深理解喔。
🔔八仙过海,智斗二分
小伙伴们对忍姐姐那把独特的日轮刀有没有印象了,感觉喃,舞起来好轻巧,看着好潇洒
但是忍姐姐的结局好容易爆泪点呀😭😭无限城中就这种牺牲了😭😭😭
害,得回归正题啦~
到蝴蝶屋中开始修习咱们今天要学的呼吸之法 —— 二分啦
💓据说只有10%的程序员可以写对二分
二分的基础用法是在单调序列或单调函数中进行查找。因此当问题具有单调性的时候,就一定可以通过二分把求解转换为判定。说通俗一点了,可理解为判断出答案在这个单调区间的位置
(根据复杂度理论,进行判定的难度小于进行求解)。
进一步,我们还可以扩展到通过三分法解决单峰函数的极值以及相关的问题。 |
二分难点在于对细节的处理: |
对于整数域上的二分,需要注意终止边界、左右区间取舍时的开闭情况,避免漏掉答案或造成死循环;
对于实数域的二分,需要注意精度问题。
🌟整数集合上的二分
使用二分法的前提是保证最终答案处于闭区间 [ l , r ] [l,r] [l,r]之内,循环以 l = r l = r l=r结束,每次二分的中间值 m i d mid mid会归属于左半段与右半段二者之一。
情况一:在单调递增序列 a a a中查找大于等于x的数最小的一个位置。
while(l < r)
{
int mid = (l+r) >> 1;
if(a[mid] >= x) r = mid ;
else l = mid + 1;
}
return a[l];
情况一用图片演示的效果如下:
情况二:在单调递增序列a中查找小于等于x的数中最大的一个位置
while(l < r)
{
int mid = (l+r+1) >> 1;
if(a[mid] <= x) l = mid ;
else r = mid - 1;
}
return a[l];
对于情况二用图片演示效果如下:
如同上面两段代码所示,这种二分写法可能会有两种形式: |
1、范围缩小时, r = m i d r=mid r=mid, l = m i d + 1 l=mid+1 l=mid+1,取中间值时, m i d = ( l + r ) > > 1 mid = (l+r)>>1 mid=(l+r)>>1
2、范围缩小时, l = m i d l=mid l=mid, r = m i d − 1 r=mid-1 r=mid−1,取中间值时, m i d = ( l + r + 1 ) > > 1 mid = (l+r+1)>>1 mid=(l+r+1)>>1
注意第二段的写法,倘若第二段也是采用 m i d = ( l + r ) > > 1 mid = (l+r)>>1 mid=(l+r)>>1,那么当 r − l = 1 r-l=1 r−l=1时,即 r = l + 1 r = l+1 r=l+1,那么就会出现:
m i d = ( r + l ) > > 1 mid = (r+l)>>1 mid=(r+l)>>1 = ( l + 1 + l ) > > 1 (l+1+l)>>1 (l+1+l)>>1 = l l l。
若接下来进入 l = m i d l=mid l=mid的分支,可行的区间并没有缩小,会造成死循环。
若进入 r = m i d