引言
笼统概括:二分算法把一个区间对半分成两部分,按某种性质每次只取一部分。然后将取的那部分再次对半分,如此往复。直到区间只剩一个数。
细心的小伙伴会对上面的加粗的字有所警觉。
对半分 ? 整数能每次都对半分吗?奇数怎么办?这涉及向上向下取整。
某种性质 ?例如 ">=x"
为一种性质,这样把区间分成 "<x"
和 ">=x"
。
只剩一个数 ? 浮点数怎么可能只剩一个数?这涉及精度问题。
整数二分(~手动音效)
真正二分之前,其实按照题目的具体意思,已经对区间按性质划成了两部分。
事实上,能二分也就意味着能对区间按某种性质划出两部分
例1,求某个有序区间第一个>=3
的数
{1, 2, 3, 3, 4, 5}
按照">=3"
划出 {1, 2}
和 {3, 3, 4, 5}
例2,求某个有序区间最后一个<=3
的数
{1, 2, 3, 3, 4, 5}
按照"<=3"
划出 {1, 2, 3, 3}
和 { 4, 5}
不管题目要求的性质是什么,对半后再按某种性质取“一半”区间,
取到最后会发现,只会取到两个数。
哪两个数? 按照性质划分成两区间,不妨叫第一区间和第二区间(或者绕一点叫左右区间)
只能取到第一区间(左区间)的右端点,
即例1中{1, 2}
的2
, 例2中 {1, 2, 3, 3}
的3
和第二区间(右区间)的左端点,
即例1中 {3, 3, 4, 5}
的3
, 例2中{ 4, 5}
的4
之后再按照题目的要求,该取啥就取啥,完事~。
实际上整数二分成了求解某个区间某个端点的方法
对应不同两个端点就会有两个模板。
求第一区间(左区间)的右端点模板
bool check(int x) {
/* ... */} // 若 q[x] <= 某个点 return ture;反之
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_1(