总目标
- 在有序数组中判断元素是否存在 —— 标准二分查找
- 在有序数组中找>=num的最左位置
- 在有序数组中找<=num的最右位置
- 二分搜索的扩展 —— 不一定要求数组有序,比如寻找峰值
- 二分答案法 —— 一类重要的算法思想(如最小化最大值、最大化最小值问题)
判断有序数组中是否存在目标数
思路
典型二分查找,时间复杂度 O(log n)
每次取中点 m,比较 arr[m] 与 num:
相等 → 返回 true
中点值大 → 右边界左移
中点值小 → 左边界右移
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static boolean exist(int[] arr, int num) {
if (arr == null || arr.length < 2) {
return false;
}
int l = 0, r = arr.length - 1, m = 0;
while (l <= r) {
m = (l + r) / 2;
if (arr[m] == num) {
return true;
} else if (arr[m] > num) {
r = m - 1;
} else if (arr[m] < num) {
l = m + 1;
}
}
return false;
}
查找有序数组 >=num 的最左位置
思路
找到满足条件的第一个位置
核心:一旦 arr[m] >= num,记录答案并继续向左二分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static int findLeft(int[] arr, int num) {
int l = 0, r = arr.length - 1, m = 0;
int ans = -1;
while (l <= r) {
// m = (l+r)/2;
// m = l + (r - l) / 2; // 防溢出
//非负数向右移动一位等于除以2
m = l + ((r - 1) >> 1);
if (arr[m] >= num) {
ans = m;
r = m - 1;
} else {
l = m + 1;
}
}
return ans;
}
查找有序数组<=num 的最右位置
思路
找到满足条件的最后一个位置
核心:一旦 arr[m] <= num,记录答案并继续向右二分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static int findright(int[] arr, int num) {
int l = 0, r = arr.length - 1, m = 0;
int ans = -1;
while (l <= r) {
m = l + ((r - l) >> 1);
if (arr[m] > num) {
r = m - 1;
} else {
ans = m;
l = m + 1;
}
}
return ans;
}
寻找峰值元素
- 判断【0】位置
- 判断【n-1】位置
- 检查【1,(n-2)】位置,看中点:
- 左>中,左侧二分
- 右>中,右侧二分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public int findPeakElement(int[] nums) {
int n = nums.length;
if(nums.length==1){
return 0;
}
if(nums[0]>nums[1]){
return 0;
}
if(nums[n-1]>nums[n-2]){
return n-1;
}
int l = 1,r=n-2,m=0,ans = -1;
while(l<=r){
m = l+((r-l)>>1);
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;
}
public static boolean test(int[] sorteArr, int num) {
for (int cur : sorteArr) {
if (cur == num) {
return true;
}
}
return false;
}
public static int[] randomArray(int n, int v) {
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = (int) (Math.random() * v) + 1;
}
return arr;
}
public static void main(String[] args) {
int N = 100;
int V = 1000;
int testTimes = 5000;
System.out.println("测试开始");
for (int i = 0; i < testTimes; i++) {
int n = (int) (Math.random() * N);
int[] arr = randomArray(n, V);
Arrays.sort(arr);
int num = (int) (Math.random() * N);
if (test(arr, num) != exist(arr, num)) {
System.out.println("出错了!");
}
}
}