booleancheck(int x){/*......*/}// 检查x是否满足某种性质staticintbSearch1(int l,int r){while(l < r){int mid = l + r +1>>1;if(check(mid)) l = mid;else r = mid -1;}return l;}staticintbSearch2(int l,int r){while(l < r){int mid = l + r >>1;if(check(mid)) r = mid;else l = mid +1;}return l;}
浮点数二分
staticdoublebSearch3(double l,double r){while(r - l >1e-8){double mid =(l + r)/2;if(check(mid)) r = mid;else l = mid;}return l;}
for(int i =0, j =0; i < n; i++){while(j < i &&check(i, j)) j++;// 具体问题的逻辑}
常用问题分类:
(1)对于一个序列,用两个指针维护一段区间
(2)对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作
离散化
staticList<Integer> alls =newArrayList<>();// 存储所有待离散的值
alls =newArrayList<>(newHashSet<>(alls));// 去重Collections.sort(alls);// 先去重再排序// 二分求出x对应的离散化的值staticintfind(int x){// 找到第一个大于等于x的位置int l =0, r = alls.size()-1;while(l < r){int mid = l + r >>1;if(alls.get(mid)>= x) r = mid;else l = mid +1;}return r +1;// 映射到1,2,...n(有利于求前缀和)}
区间合并
// 将所有存在交集的区间合并,并保存合并后的区间staticList<int[]> segs =newArrayList<>();staticList<int[]> res =newArrayList<>();staticvoidmerge(){// 区间左端点排序
segs.sort(newComparator<int[]>(){publicintcompare(int[] o1,int[] o2){return o1[0]- o2[0];}});// segs.sort((o1, o2) -> o1[0] - o2[0]); // 使用Lambda表达式会降低速度int l =Integer.MIN_VALUE, r =Integer.MIN_VALUE;for(int[] seg : segs){if(r < seg[0]){if(l !=Integer.MIN_VALUE) res.add(newint[]{l, r});
l = seg[0]; r = seg[1];}else r =Math.max(r, seg[1]);}if(l !=Integer.MIN_VALUE) res.add(newint[]{l, r});// 添加最后更新的区间}