二分法
二分法主要有两种,一种是整数二分,一种是实数二分。
整数二分
整数二分有四种情况,分别对应四个需求
-
得到等于结果的最左侧下标
-
得到等于结果的最右侧下标
-
得到第一个小于结果的下标
-
得到第一个大于结果的下标
-
得到满足结果的最左侧下标。
while(l < r){
int mid = (l+r)/2;//取中值
if(nums[mid] >= ans) r = mid;//这里有两种选择,两种选择的关键就是把等号划分到 > 这边还是 < 这边。
else l = mid+1;
}//将等号放置>这边,如果mid=ans那么区间会向左移,因此最终会取得最左侧下标。
- 得到满足结果的最右侧下标。
while(l<r){
int mid = (l+r+1)/2;
if(nums[mid] <= ans) l = mid;
else r = mid-1;
}
- 得到第一个小于结果的下标。
while(l<r){
int mid = (l+r+1)/2;
if(nums[mid] < ans) l = mid;
else r = mid-1;
}
- 得到第一个大于结果的下标。
while(l<r){
int mid = (l+r)/2;
if(nums[mid] > ans) r = mid;
else l = mid+1;
}
下面是寻找某数的范围的java实现代码
import java.util.*;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main{
public static void main(String[] args) throws IOException{
BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
String[] line1 = buffer.readLine().split(" ");
int n = Integer.valueOf(line1[0]);
int q = Integer.valueOf(line1[1]);
int[] nums = new int[n];
String[] line2 = buffer.readLine().split(" ");
for(int i = 0; i < n; i++){
nums[i] = Integer.valueOf(line2[i]);
}
while(q-- != 0){
int ans = Integer.valueOf(buffer.readLine());
int l = 0,r = n-1;
while(l < r){
int mid = (l+r)/2;
if(nums[mid] >= ans) r = mid;
else l = mid+1;
}
if(nums[l] != ans) System.out.println(-1+" "+-1);
else{
System.out.print(l+" ");
l = 0;r = n-1;
while(l<r){
int mid = (l+r+1)/2;
if(nums[mid] <= ans) l = mid;
else r = mid-1;
}
System.out.println(l);
}
}
}
}
实数二分
实数二分较为简单,不必考虑边界问题,只需要考虑精度问题。
import java.util.*;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main{
public static void main(String[] args)throws IOException{
BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
double num = Double.valueOf(buffer.readLine());
double l = -10000,r = 10000;
while(l-r < -0.0000001){//若输出6位浮点数,一般选择10e-7或10e-8.
double mid = (l+r)/2;
if(mid * mid * mid < num) l = mid;
else r = mid;
}
System.out.printf("%.6f",l);
}
}