有序数组中是否存在一个数字
普通的二分搜索
public static boolean exist(int[] arr, int num) {
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;
} else if (arr[m] > num) {
r = m - 1;
} else {
l = m + 1;
}
}
return false;
}
两个变种
有序数组中找>=num的最左位置
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 - l) >> 1);
// 中点大于等于 num,记录答案往左二分
if (arr[m] >= num) {
ans = m;
r = m - 1;
} else {
// 不记录答案往右二分
l = m + 1;
}
}
return ans;
}
有序数组中找<=num的最右位置
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);
// 中点小于等于 num,记录答案往右二分
if (arr[m] <= num) {
ans = m;
l = m + 1;
} else {
// 不记录答案往左二分
r = m - 1;
}
}
return ans;
}
二分搜索不一定只发生在有序数组
某侧必有或者某侧没有,可以考虑二分
寻找峰值问题
public int findPeakElement(int[] nums) {
int n = nums.length;
if (nums.length <= 1) {
return 0;
}
// 因为默认 nums[-1] = nums[n] = -∞
// 所以只要第一个位置的数值大于第二个位置的数值,返回 1
// 倒数第一个位置的数值大于倒数第二个位置的数值,返回n-1 即可
if (nums[0] > nums[1]) {
return 0;
}
if (nums[n - 1] > nums[n - 2]) {
return n - 1;
}
// X ↗ 中间一定有峰值点 ↘ X
// 0 1 n-2 n-1
int left = 1, right = n - 2,mid=0, ans = -1;
while (left <= right) {
mid = left + (right - left) / 2;
// 左边值大于中间值,峰值存在于左侧,左侧二分
if (nums[mid] < nums[mid - 1]) {
right = mid-1;
} else if ( nums[mid] < nums[mid + 1]) {
// 右边值小于中间值,峰值存在于右侧,右侧二分
left = mid+1;
}else {
// 中间值是峰值
ans = mid;
break;
}
}
return ans;
}
二分答案法
todo