目录
整数二分
猜数字游戏
Random random = new Random();
//生成 1 到 100 之间的随机数
int targetNumber = random.nextInt(100)+ 1;
// 初始化猜测次数
int guesscount = 0;
System.out.println("欢迎来到猜数字游戏!");
system.out. println("我已经想好了一个 1 到 100 之间的数字。试着猜猜看吧!");
//游戏主循环
while (true){
System.out.print("请输入你的猜测:");
int userGuess = in.nextInt();
guesscount+;//记录猜测次数
//判断用户的猜测
if(userGuess < targetNumber){
System.out.println("你猜的数字太小了。");
} else if (userGuess > targetNumber){
System.out.println("你猜的数字太大了。");
} else {
//用户猜中了
System.out.println("恭喜你,猜对了!你总共猜了"+ guesscount +"次。");
break;
}
}

二分原理
二分法,也叫二分查找法,是一种用于在有序数组或列表中快速查找目标元素的位置的算法。它的核心思想是通过每次将查找范围折半,逐步缩小查找范围,直到找到目标元素或确认目标不存在。复杂度是 log2n。
二分查找步骤:
1.确定初始查找区间为[l,r],其中 l是左边界,r是右边界。
2.计算中间位置mid,并判断目标值是否在区间[l,mid]还是[mid+1,r]中。
3.根据判断结果缩小查找范围,并重复该过程,直到找到目标值或查找区间为空。
例题:整数二分模版讲解
找到有序区间中=x最左边的数字的位置。
static int getL(int a[], int l, int r, int x){
while (l < r){
int mid = l + r>> 1;
if(x <= a[mid]){
r= mid;
} else {
l = mid + l;}}
if (a[l]!= x) return -1;
return l;}

找到有序区间中= α 最右边的数字的位置。
static int getR(int a[], int l, int r, int x) {
while (l <r){
int mid = l + r + 1 >> 1;
if(x< a[mid]){
r= mid - 1;
} else {
l = mid;
}}
if(a[l]!= x) return -1;
return 1;}
找到有序区间中>=x 第一个数字的位置。
static int lower_bound(int a[], int l, int r, int x) {
if (x > a[r]) return -1;
while (l <r){
int mid = l + r >> 1;
if(x<= a[mid]){
r = mid;
} else {
l = mid + 1;
}}
return 1;}
找到有序区间中>x 第一个数字的位置。
static int upper_bound(int a[], int l, int r, int x) {
if (x >= a[r]) return -1;
while (l < r){
int mid = l + r >> 1;
if (x < a[mid]){
r = mid;
} else {
l = mid + 1;
}}
return 1;
}
例题:分巧克力
给定n 个边长为 w× h的巧克力,你需要固定一个边长 a,使得巧克力可以划分成至少k块 ax a 的小巧克力。问 α最大可以是多少。
暴力做法为枚举巧克力的边长,看分出来的数量是不是满足k块。
static boolean check(int x){
long ans=0;
for(int i=1;i<=n;i++){
ans=ans+(h[i]/x)*(w[i]/x);
if(ans>=k) return true;
}
return false;
}
for(int i=1;i<=100000;i++){
if(!check(i)){
return i-1;}}
可以看出随着巧克力边长的变小,巧克力分出来的数量越多,因此是一个递减函数。具有单调性。
int l=1,r=100000;
while(l<r){
int mid=(l+r+1)/2;
if(check(mid)){
l=mid;
}else{
r=mid-1;
}
}
out.println(l);
static boolean check(int x){
long ans=0;
for(int i=1;i<=n;i++){
ans=ans+(h[i]/x)*(w[i]/x);
if(ans>=k) return true;
}
return false;
}
import java.util.Scanner;
//1:无需package
//2: 类名必须Main, 不可修改
public class lll {
static int n,k;
static int H[],W[];
static boolean check(int x) {//最大值
int res=0;
for(int i=1;i<=n;i++) {
res+=(H[i]/x)*(W[i]/x);
if(res>=k)return true;
}
return false;
}
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
n=in.nextInt();
k=in.nextInt();
H=new int[n+10];
W=new int[n+10];
for(int i=1;i<=n;i++) {
H[i]=in.nextInt();
W[i]=in.nextInt();
}
int l=1,r=100000;//权值不能太大
while(l<r) {
int mid=(l+r+1)>>1;
if(check(mid)) {
l=mid;
}else {
r=mid-1;
}
}
System.out.println(l);
}
}
浮点数二分
数的M次方根
给定一个整数 N,你需要求解 N 的 M 次方根,保留 7 位小数。
暴力思路是从 0 开始枚举,每次加 10^-7,时间复杂度太高了。
for(double i=0;i<=N;i=i+0.0000001){
double res=1;
for(int j=1;j<=M;j++){
res=res*i;
}
if(res==N){
out.println(res);
break;
}}
我们可以二分 M 次方根,二分左端点为 0,右端点为 N。
二分的终止条件我们要从 l< r变成l+ eps < r。eps 是一个误差小数,一般小数位数是 7,我们就写
10^-9次方,如果是 6,就写 10^-8。
double eps=1e-9;
double l=0,r=N;
while(l+eps<r){
double mid=(l+r)/2;
if(check(mid)) r=mid;
else l=mid;
}
代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.StringTokenizer;
public class Main{
static double eps=1e-9;
static double M;
static double N;
static boolean check(double x){
double res=1;
for(int i=1;i<=M;i++){
res=res*x;}
return res>=N ;
}
public static void main(String[] args) {
N=in.nextDouble();
M=in.nextDouble();
double l=1,r=N;
while(l+eps<r){
double mid=(l+r)/2;
if(check(mid)){
r=mid;
}else{
l=mid;
}
}
out.printf("%.7f",l);
out.flush();
}
static FastReader in=new FastReader();
static PrintWriter out=new PrintWriter(System.out);
static class FastReader{
static BufferedReader BR;
static StringTokenizer ST;
FastReader(){
BR=new BufferedReader(new InputStreamReader(System.in));
}
String next(){
String str="";
while(ST==null||!ST.hasMoreElements()){
try{str=BR.readLine();
}catch(IOException e){
throw new RuntimeException(e);}
ST=new StringTokenizer(str);
}
return ST.nextToken();
}
int nextInt(){
return Integer.parseInt(next());
}
long nextLong(){
return Long.parseLong(next());
}
public double nextDouble() {
return Double.parseDouble(next());
}
}
}