认识二分法
经常见到的类型是在一个有序数组上,开展二分搜索,但有序真的是所有问题求解时使用二分的必要条件吗?
只要能正确构建左右两侧的淘汰逻辑,你就可以二分。
二分常见题型
1>在一个有序数组中,找某个数是否存在
public static boolean exist(int[] sortedArr, int num) {
if (sortedArr == null || sortedArr.length == 0) {
return false;
}
int L = 0;
int R = sortedArr.length - 1;
int mid = 0;
// L..R
while (L < R) { // L..R 至少两个数的时候
mid = L + ((R - L) >> 1);
if (sortedArr[mid] == num) {
return true;
} else if (sortedArr[mid] > num) {
R = mid - 1;
} else {
L = mid + 1;
}
}
return sortedArr[L] == num;
}
2> 在一个有序数组中,找>=某个数最左侧的位置
// 在arr上,找满足>=value的最左位置
public static int nearestLeft(int[] arr, int value) {
int L = 0;
int R = arr.length - 1;
int index = -1; // 记录最左的对号
while (L <= R) { // 至少一个数的时候
int mid = L + ((R - L) >> 1);
if (arr[mid] >= value) {
index = mid;
R = mid - 1;
} else {
L = mid + 1;
}
}
return index;
}
3> 在一个有序数组中,找<=某个数最右侧的位置
// 在arr上,找满足<=value的最右位置
public static int nearestRight(int[] arr, int value) {
int L = 0;
int R = arr.length - 1;
int index = -1; // 记录最右的对号
while (L <= R) {
int mid = L + ((R - L) >> 1);
if (arr[mid] <= value) {
index = mid;
L = mid + 1;
} else {
R = mid - 1;
}
}
return index;
}
4> 如何获得有序数组中的指定元素的个数?
二分法:二分查找元素,然后二分查找左边界,再查找右边界,最后右边界减去左边界就是指定元素个数。
这道题实际上是如上三道题的综合。
- 在一个有序数组中,找某个数是否存在 。
- 在一个有序数组中,找>=某个数最左侧的位置 。
- 在一个有序数组中,找<=某个数最右侧的位置 。
5> 局部最小值问题
public static int getLessIndex(int[] arr) {
if (arr == null || arr.length == 0) {
return -1; // no exist
}
if (arr.length == 1 || arr[0] < arr[1]) {
return 0;
}
if (arr[arr.length - 1] < arr[arr.length - 2]) {
return arr.length - 1;
}
int left = 1;
int right = arr.length - 2;
int mid = 0;
while (left < right) {
mid = (left + right) / 2;
if (arr[mid] > arr[mid - 1]) {
right = mid - 1;
} else if (arr[mid] > arr[mid + 1]) {
left = mid + 1;
} else {
return mid;
}
}
return left;
}