大家好,我是爬行系,今天打卡的题用到了二分查找法,就顺便复习下二分模板吧
二分查找法
二分查找也就是折半查找。折半查找是将 N 个元素分成大致相同的两部分。选取中间元素与查找的的元素比较,或者与查找条件相比较,找到或者说找到下一次查找的半区。每次都将范围缩小至1/2,所以时间复杂度是 O(log2n),但是二分查找的前提是有序的,一般是从小到排列。
1.题目的特征
- 答案具有单调性;
- 二分答案的问题往往有固定的问法,比如:令最大值最小(最小值最大),求满足条件的最大(小)值等。
2.二分模板
// 在单调递增序列a中查找>=x的数中最小的一个(即x或x的后继)
while (low < high) {
int mid = (low + high) / 2;
if (a[mid] >= x)
high= mid;
else
low = mid + 1;
}
// 在单调递增序列a中查找<=x的数中最大的一个(即x或x的前驱)
while (low < high) {
int mid = (low + high + 1) / 2;//加一是避免出现死循环
if (a[mid] <= x)
low = mid;
else
high = mid - 1;
}
例题
题目描述
伐木工人 Mirko 需要砍 MM 米长的木材。对 Mirko 来说这是很简单的工作,因为他有一个漂亮的新伐木机,可以如野火一般砍伐森林。不过,Mirko 只被允许砍伐一排树。
Mirko 的伐木机工作流程如下:Mirko 设置一个高度参数 HH(米),伐木机升起一个巨大的锯片到高度 HH,并锯掉所有树比 HH 高的部分(当然,树木不高于 HH 米的部分保持不变)。Mirko 就得到树木被锯下的部分。例如,如果一排树的高度分别为 20,15,1020,15,10 和 1717,Mirko 把锯片升到 1515 米的高度,切割后树木剩下的高度将是 15,15,1015,15,10 和 1515,而 Mirko 将从第 11 棵树得到 55 米,从第 44 棵树得到 22 米,共得到 77 米木材。
Mirko 非常关注生态保护,所以他不会砍掉过多的木材。这也是他尽可能高地设定伐木机锯片的原因。请帮助 Mirko 找到伐木机锯片的最大的整数高度 HH,使得他能得到的木材至少为 MM 米。换句话说,如果再升高 11 米,他将得不到 MM 米木材。
输入格式
第 11 行 22 个整数 NN 和 MM,NN 表示树木的数量,MM 表示需要的木材总长度。
第 22 行 NN 个整数表示每棵树的高度。
输出格式
11 个整数,表示锯片的最高高度。
题目链接
AC代码
import java.io.*;
public class Main {
static long N,M;
static long[] tree;
//快速输入
static BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
static StreamTokenizer st=new StreamTokenizer(br);
public static void main(String[] args) throws IOException {
N=nextLong();
M=nextLong();
tree=new long[1000010];
long maxlen=0;
for(int i=0;i<N;i++){
tree[i]=nextLong();
if(tree[i]>maxlen){
maxlen=tree[i];//树中最高的高度
}
}
long low=0,high=maxlen;
while(low<high){
long mid=(low+high+1)/2;
if(check(mid)){
low=mid;
}else{
high=mid-1;
}
}
System.out.println(low);
}
public static boolean check(long mid){
long sum=0;
for(int i=0;i<N;i++){
if(tree[i]>mid){
sum+=tree[i]-mid;
}
}
if(sum>=M){//说明该锯片高度太低了,意味着锯片高度再mid的右边,故low=mid;
return true;
}else{
return false;
}
}
public static long nextLong() throws IOException{
st.nextToken();
return (long)st.nval;
}
}