在有序数据集合中,查找某个值
static int binarySearch(int[] a, int value) {
int low = 0;
int high = a.length - 1;
while (low <= high) {
int min = low + ((high - low) >> 1);
if (a[min] == value) {
return min;
} else if (a[min] < value) {
low = min + 1;
} else {
high = high - 1;
}
}
return -1;
}
说明:
1. 循环条件 是 low <= high,而不是 low < high;
2. mid=(low+high)/2 容易导致数据溢出(Integer占4个字节,虽然通常数据集合中没那么多数据),所以这里写成 min = low + ((high - low) >> 1);
3. low 和 high 的更新,不能写成 low = min 、 high = min。可能会造成 low = high,导致一直循环。
二分查找的变种
- 查找第一个等于给定值的数据
- 查找最后一个值等于给定值的元素
- 查找第一个大于等于给定值的元素
- 查找最后一个小于等于给定值的元素
1. 查找第一个等于给定值的数据
public static int findFirstEq(int[] a, int value) {
int low = 0;
int high = a.length - 1;
while (low <= high) {
int mid = low + ((high - low) >> 1);
if (a[mid] > value) {
high = mid - 1;
} else if (a[mid] < value) {
low = mid + 1;
} else {
if ((mid == 0) || (a[mid - 1] != value))
return mid;
else
high = mid - 1;
}
}
return -1;
}
2. 查找最后一个值等于给定值的元素
public int findLastEq(int[] a, int value) {
int n = a.length;
int low = 0;
int high = n - 1;
while (low <= high) {
int mid = low + ((high - low) >> 1);
if (a[mid] > value) {
high = mid - 1;
} else if (a[mid] < value) {
low = mid + 1;
} else {
if ((mid == n - 1) || (a[mid + 1] != value))
return mid;
else
low = mid + 1;
}
}
return -1;
}
3. 查找第一个大于等于给定值的元素
public int findFirstGTEQ(int[] a, int value) {
int low = 0;
int high = a.length - 1;
while (low <= high) {
int mid = low + ((high - low) >> 1);
if (a[mid] >= value) {
if ((mid == 0) || (a[mid - 1] < value))
return mid;
else
high = mid - 1;
} else {
low = mid + 1;
}
}
return -1;
}
4. 查找最后一个小于等于给定值的元素
public int findFirstLTEQ(int[] a, int value) {
int n = a.length - 1;
int low = 0;
int high = n - 1;
while (low <= high) {
int mid = low + ((high - low) >> 1);
if (a[mid] > value) {
high = mid - 1;
} else {
if ((mid == n - 1) || (a[mid + 1] > value))
return mid;
else
low = mid + 1;
}
}
return -1;
}
扩展: letcode 33 题
static int text(int[] a, int value) {
if (a == null || a.length == 0) {
return -1;
}
int low = 0;
int high = a.length - 1;
while (low <= high) {
int min = low + ((high - low) >> 1);
if (a[min] == value) {
return min;
}
if (a[low] <= a[min]) {
// min 前半部分是有序数组,后半部分是有序循环数组
if (a[low] <= value && a[min] > value) {
high = min - 1;
} else {
low = min + 1;
}
} else {
// min 后半部分是有序数组,前半部分是有序循环数组
if (a[min] < value && a[high] >= value) {
low = min + 1;
} else {
high = min - 1;
}
}
}
return -1;
}