二分查找法02:二分查找法的变种
upper
查找大于target的第一个元素
public class Algorithm {
public static void main(String[] args) {
Integer[] arr = {1, 1, 3, 3, 5, 5};
for (int i = 0; i <= 6; i++) {
System.out.print(BinarySearch.upper(arr, i) + " "); //0 2 2 4 4 6 6
}
}
}
class BinarySearch {
/**
* 循环不变量:在arr[left, right]中查找大于target的第一个元素,如果找不到,就返回arr.length
*/
public static<E extends Comparable<E>> int upper(E[] arr, E target){
int left = 0;
/**
* 找不到会返回arr.length,因此right要取到arr.length
*/
int right = arr.length;
while (left < right) {
int mid = left + (right - left) / 2;
if (arr[mid].compareTo(target) <= 0) {
left = mid + 1;
}
else {
/**
* 此时mid有可能是要找的元素,因此不能省略
*/
right = mid;
}
}
return left;
}
}
upper_ceil
若target有多个,则返回索引值最大的那个;若不存在,则返回大于target的第一个元素,也即upper()方法的结果
public class Algorithm {
public static void main(String[] args) {
Integer[] arr = {1, 1, 3, 3, 5, 5};
for (int i = 0; i <= 6; i++) {
System.out.print(BinarySearch.upper_ceil(arr, i) + " "); //0 1 2 3 4 5 6
}
}
}
class BinarySearch {
public static<E extends Comparable<E>> int upper_ceil(E[] arr, E target) {
int index = upper(arr, target);
/**
* 先执行upper()得到index,这是大于target的第一个元素
* 如果target存在,就返回其最大的索引index - 1,不存在就返回upper()
*/
if (index - 1 >= 0 && arr[index - 1].compareTo(target) == 0){
return index - 1;
}
else {
return index;
}
}
public static<E extends Comparable<E>> int upper(E[] arr, E target){
int left = 0;
int right = arr.length;
while (left < right) {
int mid = left + (right - left) / 2;
if (arr[mid].compareTo(target) <= 0) {
left = mid + 1;
}
else {
right = mid;
}
}
return left;
}
}
lower_ceil
若target有多个,则返回索引值最小的那个;若不存在,则返回大于target的第一个元素,也即upper()方法的结果
和upper()相比,区别只在于判断条件arr[mid].compareTo(target) < 0和<=0
public class Algorithm {
public static void main(String[] args) {
Integer[] arr = {1, 1, 3, 3, 5, 5};
for (int i = 0; i <= 6; i++) {
System.out.print(BinarySearch.lower_ceil(arr, i) + " "); //0 0 2 2 4 4 6
}
}
}
class BinarySearch {
public static<E extends Comparable<E>> int lower_ceil(E[] arr, E target) {
int left = 0;
int right = arr.length;
while (left < right) {
int mid = left + (right - left) / 2;
/**
* 因为要返回target的最小索引,如果target在mid右边,那肯定mid不是要找的元素
*/
if (arr[mid].compareTo(target) < 0) {
left = mid + 1;
}
else {
/**
* 如果target在mid左边,mid有可能是要找的元素,不能省略
*/
right = mid;
}
}
return left;
}
}
lower
查找小于target的最后一个元素
注意死循环
public class Algorithm {
public static void main(String[] args) {
Integer[] arr = {1, 1, 3, 3, 5, 5};
for (int i = 0; i <= 6; i++) {
System.out.print(BinarySearch.lower(arr, i) + " "); //-1 -1 1 1 3 3 5
}
}
}
class BinarySearch {
/**
* 循环不变量:在arr[left, right]中寻找小于target的最后一个元素,如果找不到,就返回-1
*/
public static <E extends Comparable<E>> int lower(E[] arr, E target) {
/**
* 找不到会返回-1,因此left要取到-1
*/
int left = -1;
int right = arr.length - 1;
while (left < right) {
/**
* 在缩小区间的过程中,会出现left和right相邻的情况,因为计算机默认是向下取整的,因此mid == (left + right) / 2 == left
* 当arr[mid].compareTo(target) < 0时,left始终等于mid,[mid, right]始终不会变,就会陷入死循环。
* 在求mid值时加1,就会变成向上取整,可以避免这个死循环
*/
int mid = left + (right - left + 1) / 2;
if (arr[mid].compareTo(target) < 0) {
left = mid;
} else {
/**
* 如果arr[mid] >= target,mid肯定不是要找的元素
*/
right = mid - 1;
}
}
return left;
}
}
lower_floor
若target有多个,则返回索引值最小的那个;若不存在,则返回小于target的最后一个元素,也即lower()方法的结果
public class Algorithm {
public static void main(String[] args) {
Integer[] arr = {1, 1, 3, 3, 5, 5};
for (int i = 0; i <= 6; i++) {
System.out.print(BinarySearch.lower_floor(arr, i) + " "); //-1 0 1 2 3 4 5
}
}
}
class BinarySearch {
public static<E extends Comparable<E>> int lower_floor(E[] arr, E target) {
int index = lower(arr, target);
/**
* 先执行lower()得到index,这是小于target的最大值
* 如果target存在,就返回其最小的索引index + 1,不存在就返回lower()
*/
if (index + 1 < arr.length && arr[index + 1].compareTo(target) == 0){
return index + 1;
}
else {
return index;
}
}
public static <E extends Comparable<E>> int lower(E[] arr, E target) {
int left = -1;
int right = arr.length - 1;
while (left < right) {
int mid = left + (right - left + 1) / 2;
if (arr[mid].compareTo(target) < 0) {
left = mid;
} else {
right = mid - 1;
}
}
return left;
}
}
upper_floor
若target有多个,则返回索引值最大的那个;若不存在,则返回小于target的最后一个元素,也即lower()方法的结果
public class Algorithm {
public static void main(String[] args) {
Integer[] arr = {1, 1, 3, 3, 5, 5};
for (int i = 0; i <= 6; i++) {
System.out.print(BinarySearch.upper_floor(arr, i) + " "); //-1 1 1 3 3 5 5
}
}
}
class BinarySearch {
/**
* 循环不变量:在arr[left, right]中寻找小于target的最后一个元素,如果找不到,就返回-1
*/
public static <E extends Comparable<E>> int upper_floor(E[] arr, E target) {
/**
* 找不到会返回-1,因此left要取到-1
*/
int left = -1;
int right = arr.length - 1;
while (left < right) {
int mid = left + (right - left + 1) / 2;
if (arr[mid].compareTo(target) <= 0) {
left = mid;
} else {
/**
* 如果arr[mid] > target,mid肯定不是要找的元素
*/
right = mid - 1;
}
}
return left;
}
}
二分查找法模板
class BinarySearch {
public static <E extends Comparable<E>> int **(E[] arr, E target) {
int left = **;
int right = **;
/**
* 在arr[left, right]中寻找解
*/
while (left < right) {
int mid = **;
if (arr[mid].compareTo(target) ** 0){
**;
}
else {
**;
}
}
return left;
}
}