一.二分查找法--(极客时间记录)
二分查找法能解决的问题,更倾向于用散列表或者二叉树。二分法更适用于近似的查找问题。
容易出错的细节:
- 终止条件;
- 区间上下界更新的方法;
- 返回值的选择;
import java.util.Scanner;
import java.util.Arrays;
public class BinaraySearch {
public static int rank(int key,int[] a) {
int lo=0;
int hi=a.length-1;
while(lo<=hi) {
int mid=lo+(hi-lo)/2;
if(key<a[mid]) hi=mid-1;
else if(key>a[mid]) lo=mid+1;
else return mid;
}
return -1;
}
public static int bssearch(int key,int[] a) {
return bsearchInternally(key, a, 0, a.length-1);
}
private static int bsearchInternally(int key, int[] a, int low, int high) {
// TODO Auto-generated method stub
int mid = low + ((high - low)>>1);
if(a[mid] == key) return mid;
else if(a[mid] > key) {
return bsearchInternally(key, a, low, mid -1);
}else if(a[mid] < key) {
return bsearchInternally(key, a, mid+1, high);
}
return 0;
}
//变式1---如果排序的数组中有重复出现的数字,找出第一个相等的数字
public static int bsearchQuestion1(int value, int[] a) {
int low = 0;
int high = a.length - 1;
while(low <= high) {
int mid = low + ((high - low)>>1);
if(a[mid] < value) {
low = mid +1;
}else if(a[mid] > value) {
high = mid - 1;
}else {//发生修改的地方
if((mid == 0) || (a[mid - 1] != value)) return mid;//若果mid到了0,那前面肯定没有数字了,如果前面和value相等,则修改high
else high = mid - 1;
}
}
return -1;
}
//变式2---如果排序的数组中有重复出现的数字,找出最后一个相等的数字
public static int bsearchQuestion2(int value, int[] a) {
int low = 0;
int high = a.length - 1;
while(low <= high) {
int mid = low + ((high - low)>>1);
if(a[mid] < value) {
low = mid +1;
}else if(a[mid] > value) {
high = mid - 1;
}else {//发生修改的地方
if((mid == a.length - 1) || (a[mid + 1] != value)) return mid;//若果mid到了0,那前面肯定没有数字了,如果前面和value相等,则修改high
else low = mid + 1;
}
}
return -1;
}
//变式3---找出第一个大于等于给定值的数字
public static int bsearchQuestion3(int value, int[] a) {
int low = 0;
int high = a.length - 1;
while(low <= high) {
int mid = low + ((high - low)>>1);
if(a[mid] < value) {
low = mid + 1;
}else {
if((mid == 0) || (a[mid - 1] < value))return mid;
else high = mid -1;
}
}
return -1;
}
//变式4---找出最后一个小于等于给定值的数字
public static int bsearchQuestion4(int value, int[] a) {
int low = 0;
int high = a.length - 1;
while(low <= high) {
int mid = low + ((high - low)>>1);
if(a[mid] < value) {
low = mid + 1;
}else {
if((mid == a.length - 1) || (a[mid + 1] > value))return mid;
else low = mid + 1;
}
}
return -1;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
//标准输入,读取分割后转换成int
System.out.println("输入数组:");
Scanner sc = new Scanner(System.in);
String str = sc.nextLine().toString();
String arr[] = str.split(" ");
int[] a = new int[arr.length];
for(int j=0;j<=a.length-1;j++) {
a[j] = Integer.parseInt(arr[j]);
//System.out.print(a[j] + " ");
}
Arrays.sort(a);
System.out.println("输入要查询的数");
Scanner x=new Scanner(System.in);
int number = x.nextInt();
System.out.println(bsearchQuestion3(number,a));
}
}
思考题:当给定的数组是循环有序的数组,如何实现二分查找算法;
题目对应Leetcode33.