[算法][深入讨论] 更透彻地理解二分法
二分虽简单,细节很难改。研究不深入,用时两行泪。
你知道吗?在所有懂二分法的人中,只有8%的人能够完全掌握二分法
上升序
贴入模板(上升序)(its表示要找的数),最终可以使用 left 当做寻找到的数:
1 int left = 0,right = n - 1; 2 int mid; 3 while(left != right){ 4 mid = (left + right) / 2; 5 if(its <= SortedList[mid]) right = mid; 6 else left = mid + 1; 7 }
二分法必然会碰到 left + 1 == right 的情况,此时 mid == left,在这种情况将时讨论:
- 若its刚好不在SortedList中,此时一定有 SortedList(left) == SortedList(mid) < its < SortedList(right),那么必定向右缩进(改变left保留right)使 left = mid +1 == right,即最终寻找的是第一个比list大的数
- 若只有一个its在Sortedlist中,那么此时一定有 SortedList(left) == its 或者 SortedList(right) == its,但是无论哪一种情况,都会使 left== right == SortedList-1(its) (-1次表示反函数),即最终寻找的是那个唯一等于its的数
- 若有多个its在Sortedlist中,那么此时一定有 SortedList(left) == SoredList(right) == its,此时寻找的一定是List中等于its,但是我们想要知道寻找的是第几个等于its的数。若已经达到SortedList(left) == SoredList(right) == its的情况,此时一定是往左缩进(改变right = mid,保留left),即最终变化是寻找的是当前第一个等于its的数。由于每次在等于的情况都会向左缩进,所以在多个its在Sortedlist中,必定寻找的是第一个等于its的数
所以该算法求的是 从左到右第一个大于或者等于its的数
下降序
关于下降序就是把代码第5行的 <= 改为 >=
那么同理,该算法求的是 从左到右第一个小于或者等于its的数
总结
整体来看,该二分法是在不包含its是偏右方(第一个大于/第一个小于),在包含its中是偏左方(第一个等于)
以下括号内为下降序,括号外是上升序
若序列就是要找 第一个比its大于(小于)或者 等于 的数,那么直接套用SortedList(left)即可
若想要找到 第一个比its大于(小于) 的数,那么可以加一条 while(SortedList(left) != its) left++
若想要找到 最后一个比 its 小于(大于) 的数,只需要 left - 1 即可
若想要找到 最后一个比its小于(大于) 或者 等于 的数,那么加一条while(SortedList(left) != its) left++ 后再让 left - 1 即可。