下面给出二分搜索的四个经典例题,快速学习二分搜索
1、在有序数组中确定num是否存在
给定一个升序数组arr,判断一个数num是否在这个升序数组中,要求时间复杂度为O(logn)。
需要使用二分搜索,若直接遍历时间复杂度为O(n),不符合要求,下面给出java代码。
public class FindNum {
public static void main(String[] args) {
int[] arr = {1, 3, 5, 7, 9};
System.out.println(exist(5, arr)); //输出true
}
public static boolean exist(int num, int[] arr) {
if (arr == null || arr.length == 0) {
return false;
}
int l = 0, r = arr.length - 1, m = 0;
while (l <= r) {
m = (l + r) / 2;
if (arr[m] == num) {
return true; //中点位置的数就是所查找的num,直接返回true
} else if (arr[m] > num) { //中点位置的数大于num,因此要往中点左边的位置查找
r = m - 1;
} else {
l = m + 1; //中点位置的数小于num,因此要往中点右边的位置查找
}
}
return false;
}
}
2、在有序数组中找>=num的最左位置
给定一个升序数组arr,并给出一个数num,求出这个数组中大于等于num的最左索引。要求时间复杂度为O(logn)。
public class FindLeft {
public static void main(String[] args) {
int[] arr = {1, 3, 3, 3, 9};
System.out.println(findLeft(3, arr)); //输出1
}
public static int findLeft(int num, int[] arr) {
int l = 0, r = arr.length - 1, m = 0, ans = -1;
while (l <= r) {
m = (l + r) / 2;
if (arr[m] >= num) {
ans = m;
r = m - 1; //中点的数大于等于num,记下中点的位置,再去中点左边找
} else {
l = m + 1;
}
}
return ans;
}
}
3、在有序数组中找<=num的最右位置
给定一个升序数组arr,并给出一个数num,求出这个数组中小于等于num的最右索引。要求时间复杂度为O(logn)。
public class FindRight {
public static void main(String[] args) {
int[] arr = {1, 3, 3, 3, 9};
System.out.println(findRight(3, arr)); //输出3
}
public static findRight(int num, int[] arr) {
int l = 0, r = arr.length - 1, m = 0, ans = 0;
while (l <= r) {
m = (l + r) / 2;
if (arr[m] <= num) {
ans = m;
l = m + 1; //中点的数小于等于num,记下中点的位置,去中点的右边找
} else {
r = m - 1;
}
return ansl
}
}
}
4、寻找峰值(leetcode原题)
峰值元素是指其值严格大于左右相邻值的元素。
给你一个整数数组nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。
要求时间复杂度为O(logn),因此需要用二分查找法。
public class FindPeak {
public static int findPeak(int[] nums) {
int n = nums.length;
if (n == 1) {
return 0; //若长度为1,峰值就是这个数组中唯一的这个数,因为默认-1和n位置都是无穷小
}
if (nums[0] > nums[1]) {
return 0; //若0位置大于1位置,返回0位置,因为-1位置无穷小
}
if (nums[n - 1] > nums[n - 2]) {
return n-1; //若n-1位置大于n-2位置,返回n-1位置,因为n位置无穷小
}
int l = 1, r = n-2, m = 0, ans = -1;
while(l <= r) {
m = (l + r) / 2;
if (nums[m - 1] > nums[m]) {
r = m - 1;
} else if (nums[m + 1] > nums[m]) {
l = m + 1;
} else {
ans = m;
break;
}
}
return ans;
}
}