二分查找法在算法题的运用
二分法主要作用是缩短查找时间
贪吃的小Q(2018腾讯秋招)
【题目描述】小Q的父母要出差N天,走之前给小Q留下了M块巧克力。小Q决定每天吃的巧克力数量不
少于前一天吃的一半,但是他又不想在父母回来之前的某一天没有巧克力吃,请问他第一天最多能吃多少 块巧克力.
对于这道题,第一印象是求 由等比数列和S 形成的不等式的解。
这个不等式大致形式为 S <=M ,但是如何解不等式呢?
由于巧克力的数量是给定了的M,那么解总在 区间【0,M )之间的整数。
可以从1开始逐个找解,但是太慢。
二分法有个转换形式是查找区间中小于KEY的最小值,所以可以用二分法解不等式。
注意,用二分法的时候要注意边界问题(Left,right)
JAVA源码如下
import java.util.Scanner;
public class Kakulate {
public static void main(String[] args) {
int m,n;
Scanner sc=new Scanner(System.in);
n=sc.nextInt();//天
m=sc.nextInt();//数量
int res=0,mid=0;
int left=1,right=m;
while(left<=right) {//二分查找
mid=(left+right+1)/2;
res=sum(mid,n);
if(res==m) {
break;
}
else if(res>m) {
right=mid-1;
}
else if(res<m) {
left=mid-1;
}
}
System.out.println(left);
}
static int sum(int s,int n) {//计算总共吃的巧克力数
int su = 0;
for(int i=0;i<n;i++) {
su +=s;
s=(s+1)/2;
}
return su;
}
}
如果逐个找肯定超时,2分法能更快的找出解。二分法的时间复杂度为 O(log2 n)
跳柱子问题
字节跳动2019春招题,现在还没公布吧,具体名字还有内容记不清了,简单的说就是
有n个柱子,第i个柱子高度为H(i) ,一个机器人当前位置在0(无柱子),机器人当前能量为E,跳向柱子i,如果E>H(I),则机器人能量增加
E-H(I),否则机器人的能量减去H(I)-E,问一开始需要至少多少能量才能全部跳过去?
计算一下E,可以发现不管E大于还是小于H,都是E=2*E-H。不难看出是 求经过所有柱子后 始终满足E>=0的解。
故可以用二分法求解,再确定区间,如果能量为H的最大值M,那么所有小于M的柱子都会为机器人增加能量,一定能跳过。
区间应为 【0 ,H的最大值】
JAVA源码如下
import java.util.Scanner;
//<2s
public class Testzhijie3 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n=sc.nextInt();
int[] h=new int[n];
for(int i=0;i<n;i++) {
h[i]=sc.nextInt();
}
int max=0,l=0,r=0, mid=0;
for(int i=0;i<n;i++) {
if(h[i]>max) {
max=h[i];
}
}
r=max;
while(l<=r) {
mid=(l+r)/2;
if(judge(mid,h)) {
r=mid-1;
}else {
l=mid+1;
}
}
System.out.println(right);
}
static boolean judge(int x,int[] a) {//判断是否满足条件
for(int i=0;i<a.length;i++) {
x=2*x-a[i];
if(x<0)
return false;
}
return true;
}
}
总结
二分查找法的优点是减少查找时间,解不等式是因为可以较快的查找出解(在log2 n的时间内完成,较快),但是注意解题时要先确定区间。