二分算法最重要的就是边界问题,边界一定要确定好,并且自己也要清晰,要不然就会混乱。
什么时候用到二分呢?当涉及到快速筛选有序序列的时候就应该想到,其实二分也经常跟排序算法结合着一起使用
关键模板
一个是确立左端点的
while(l < r) { // 确立左端点int mid = l + r >> 1;if(a[mid] >= x) r = mid;else l = mid + 1;}
想一想退出这个循环的时候是不是
l>=r
的时候,如果找到这个数的时候即l==r
的时候,l = mid + 1,即左端点不断地向右边靠近,所以这是确立左端点的同理右端点
确立右端点的
while(l < r) { // 确立右端点int mid = l + r + 1>> 1;if(a[mid] <= x) l = mid;else r = mid - 1;}
数的范围
原题目
给定一个按照升序排列的长度为 n的整数数组,以及 q个查询。
对于每个查询,返回一个元素k的起始位置和终止位置(位置从 00 开始计数)。
如果数组中不存在该元素,则返回 -1 -1
。
输入格式
第一行包含整数 n和 q,表示数组长度和询问个数。
第二行包含 n个整数(均在 1∼100001∼10000 范围内),表示完整数组。
接下来q行,每行包含一个整数 k,表示一个询问元素。
输出格式
共q行,每行包含两个整数,表示所求元素的起始位置和终止位置。
如果数组中不存在该元素,则返回 -1 -1
。
数据范围
1≤n≤1000001≤≤100000
1≤q≤100001≤≤10000
1≤k≤10000
代码:
import java.util.*;public class Main {public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();int q = in.nextInt();int[] a = new int[n];for(int i =0 ;i < n;i ++) { // 这里千万不能从1开始,要不然答案会错a[i] = in.nextInt();}while(q > 0) {q--;int x = in.nextInt();int l = 0, r = n - 1;while(l < r) { // 确立左端点int mid = l + r >> 1;if(a[mid] >= x) r = mid;else l = mid + 1;}if(a[l] != x) {System.out.println("-1 -1");continue;}System.out.print(l + " ");r = n - 1;while(l < r) { // 确立右端点int mid = l + r + 1>> 1; // 一定要注意这里有个+1if(a[mid] <= x) l = mid;else r = mid - 1;}System.out.println(l);}}}
数的三次方根
原题目
给定一个浮点数 n,求它的三次方根。
**
输入格式**
共一行,包含一个浮点数 n。
输出格式
共一行,包含一个浮点数,表示问题的解。
注意,结果保留 66 位小数。
数据范围
−10000≤n≤10000
输入样例:
1000.00
输出样例:
10.000000
代码:
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner in = new Scanner(System.in);double n = in.nextDouble();double l = -1000,r = 1000;while(r - l > 1e-8) {double mid = (r + l) / 2;if(mid * mid * mid >= n) {r = mid;} else {l = mid;}}System.out.printf("%.6f",l);}
}