模板
整数二分
- 如果有单调性,一定可以二分;但是可以二分的题目,不一定有单调性
- 所以二分的本质并不是单调性,而是寻找满足某种性质的边界
-
第一种情况是判断mid是否满足红色性质,寻找的是红色部分的边界
-
第二种情况是判断mid是否满足绿色性质,寻找的是绿色部分的边界
-
为什么第一种情况要+1
- 考虑到 l = r - 1 的情况,此时的 mid = l (除法向下取整),check后为true,陷入死循环
-
C++
bool check(int x) {/* ... */} // 检查x是否满足某种性质
// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int binary_search_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid; // check()判断mid是否满足性质
else l = mid + 1;
}
return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int binary_search_2(int l, int r)
{
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
- Java
//检查x是否满足某种性质
public static boolean check(int x) {
/*....*/
}
//区间[l, r]被划分为[l, mid]和[mid + 1, r]时使用
//寻找左边界
public static int binarch_search_1(int l, int r) {
while (l < r) {
int mid = l + r >> 1;
if (check(mid)) {
r = mid;
} else {
l = mid + 1;
}
}
return l;
}
//区间[l, r]被划分为[l, mid - 1]和[mid , r]时使用
//寻找右边界
public static int binarch_bsearch_2(int l, int r) {
while (l < r) {
int mid = l + r + 1 >> 1;
if (check(mid)) {
l = mid;
} else {
r = mid - 1;
}
}
return l;
}
浮点数二分
- 浮点数二分就不会出现边界问题
练习
01 数的范围
- 题目
- 题解
import java.io.*;
public class Main {
public static final int N = 100010;
public static int[] arr = new int[N];
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] str1 = br.readLine().split(" ");
int n = Integer.parseInt(str1[0]);
int q = Integer.parseInt(str1[1]);
String[] str2 = br.readLine().split(" ");
for (int i = 0; i < n; i++) {
arr[i] = Integer.parseInt(str2[i]);
}
while (q-- > 0) {
int k = Integer.parseInt(br.readLine());
int l = 0, r = n - 1;
while (l < r) {
int mid = l + r >> 1;
if (arr[mid] >= k) {
r = mid;
} else {
l = mid + 1;
}
}
if (arr[l] != k) {
System.out.println("-1 -1");
} else {
System.out.print(l + " ");
l = 0;
r = n - 1;
while(l < r) {
int mid = l + r + 1 >> 1;
if (arr[mid] <= k) {
l = mid;
} else {
r = mid - 1;
}
}
System.out.println(l);
}
}
br.close();
}
}
02 数的三次方根
- 题目
- 题解
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
double n = Double.parseDouble(br.readLine());
double l = -10000;
double r = 10000;
while (r - l > 1e-8) { //注意这里题目要求保留6位小数,一般要多往后算两位保证精确
double mid = (l + r) / 2;
if (mid * mid * mid > n) {
r = mid;
} else {
l = mid;
}
}
System.out.printf("%.6f\n", l);
}
}