二分查找(折半查找)只能使用在一个有序的数组(升序或降序)中查找目标元素,若数组无序则先排序。
若数组中有重复元素,则二分查找的下标可能不是唯一的。
核心思想是不断减小搜索范围,减少搜索时间。
以升序为例,比较一个元素与数列中间值的大小,若中间值比元素大则在前半部分搜索目标元素,若中间值比元素小则在后半部分搜索目标元素,若中间值与元素相等则找到元素位置。
左闭右闭区间模板:
static int binary(int nums[],int target) {
int l = 0;
int r = nums.length-1;
int mid = l+(r-l)/2;
while(r>=l) {
mid = l+(r-l)/2;
if(nums[mid]>target) {
r = mid-1;
}
else if(nums[mid]<target) {
l = mid +1;
}else {
return mid;
}
}
return -1;
}
例题:
洛谷P2249查找
package 二分查找;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
public class P2249查找 {
static StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in))); //快读
static int n;
static int m;
static int q;
static int a[]; //待查询数字
static int nextInt() throws IOException { //快读
st.nextToken();
return (int)st.nval;
}
static int binary(int q) {
int l = 0;
int r = a.length-1;
int mid = l+((r-l)>>1);
while(r>=l) {
mid = l+((r-l)>>1);
if(a[mid]==q && a[mid-1]!=q) {
return mid;
}
if( a[mid] < q) {
l = mid+1;
}
if(a[mid]>q) {
r = mid - 1;
}
}
return -1;
}
public static void main(String[] args) throws IOException {
PrintWriter pr =new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out))); //快写
n = nextInt();
m = nextInt();
a = new int[n+1]; //这里+1是因为答案中寻找到的下标是从1开始算的
for(int i = 1;i<=n;i++) {
a[i] = nextInt();
}
for(int i = 1;i<=m;i++) {
q = nextInt();
pr.print(binary(q)+" "); //快写
}
pr.flush(); //快写
}
}
LeetCode 35.搜索插入位置
package 二分查找;
import java.util.Scanner;
/*
* 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。
* 如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
*/
public class 搜索插入位置 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int nums[] = new int[n];
for(int i = 0;i<n;i++) {
nums[i] = sc.nextInt();
}
int target = sc.nextInt();
int l = 0;
int r = nums.length-1;
int mid = l+((r-l)>>1);
while(r>=l) {
mid = l+((r-l)>>1);
if(nums[mid]>target) {
r = mid-1;
}
if(nums[mid]<target) {
l = mid+1;
}
if(nums[mid]==target) {
System.out.println(mid);
break;
}
}
if(l>r) {
mid = (l+r)/2;
System.out.println(mid);
}
}
}