您可以使用Arrays.binarySearch(int[] a, int key),然后相应地调整返回值,而不是实现自己的二进制搜索。
返回搜索键的索引,如果它包含在数组中;否则,(-(插入点) - 1)。 插入点被定义为键将被插入到数组中的点:第一个元素的索引大于键,或者如果数组中的所有元素都小于,则为 a.length指定的键。请注意,这保证了当且仅当找到键时,返回值将 >= 0。
您的规则没有指定当有多个有效选择时要返回哪个索引(#3 或 #4 具有多个相等的值,或 #5 具有等距值),因此下面的代码具有明确选择的代码。如果您不关心歧义,可以删除额外的代码,或者如果您不同意我解决问题的决定,可以更改逻辑。
注意,当返回值为returnValue = -insertionPoint - 1,表示insertionPoint = -returnValue - 1,在下面的代码中表示-idx - 1。因此,插入点之前的索引是-idx - 2。
这些方法当然可能返回超出范围的索引值(-1 或 arr.length),因此调用者总是需要检查这一点。对于closest() 方法,只有当数组为空时才会发生这种情况,在这种情况下它会返回-1。
public static int smaller(int[] arr, int target) {
int idx = Arrays.binarySearch(arr, target);
if (idx < 0) {
// target not found, so return index prior to insertion point
return -idx - 2;
}
// target found, so skip to before target value(s)
do {
idx--;
} while (idx >= 0 && arr[idx] == target);
return idx;
}
public static int smallerOrEqual(int[] arr, int target) {
int idx = Arrays.binarySearch(arr, target);
if (idx < 0) {
// target not found, so return index prior to insertion point
return -idx - 2;
}
// target found, so skip to last of target value(s)
while (idx < arr.length - 1 && arr[idx + 1] == target) {
idx++;
}
return idx;
}
public static int biggerOrEqual(int[] arr, int target) {
int idx = Arrays.binarySearch(arr, target);
if (idx < 0) {
// target not found, so return index of insertion point
return -idx - 1;
}
// target found, so skip to first of target value(s)
while (idx > 0 && arr[idx - 1] == target) {
idx--;
}
return idx;
}
public static int bigger(int[] arr, int target) {
int idx = Arrays.binarySearch(arr, target);
if (idx < 0) {
// target not found, so return index of insertion point
return -idx - 1;
}
// target found, so skip to after target value(s)
do {
idx++;
} while (idx < arr.length && arr[idx] == target);
return idx;
}
public static int closest(int[] arr, int target) {
int idx = Arrays.binarySearch(arr, target);
if (idx >= 0) {
// target found, so skip to first of target value(s)
while (idx > 0 && arr[idx - 1] == target) {
idx--;
}
return idx;
}
// target not found, so compare adjacent values
idx = -idx - 1; // insertion point
if (idx == arr.length) // insert after last value
return arr.length - 1; // last value is closest
if (idx == 0) // insert before first value
return 0; // first value is closest
if (target - arr[idx - 1] > arr[idx] - target)
return idx; // higher value is closer
return idx - 1; // lower value is closer, or equal distance
}
测试
public static void main(String... args) {
int[] arr = {1, 4, 3, 1, 4, 6};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
System.out.println(" | Index | Value |");
System.out.println(" | < <= ~ >= > | < <= ~ >= > |");
System.out.println("--+----------------------+---------------------+");
for (int i = 0; i <= 7; i++)
test(arr, i);
}
public static void test(int[] arr, int target) {
int smaller = smaller (arr, target);
int smallerOrEqual = smallerOrEqual(arr, target);
int closest = closest (arr, target);
int biggerOrEqual = biggerOrEqual (arr, target);
int bigger = bigger (arr, target);
System.out.printf("%d | %3d %3d %3d %3d %3d |%3s %3s %3s %3s %3s | %d%n", target,
smaller, smallerOrEqual, closest, biggerOrEqual, bigger,
(smaller < 0 ? "" : String.valueOf(arr[smaller])),
(smallerOrEqual < 0 ? "" : String.valueOf(arr[smallerOrEqual])),
(closest < 0 ? "" : String.valueOf(arr[closest])),
(biggerOrEqual == arr.length ? "" : String.valueOf(arr[biggerOrEqual])),
(bigger == arr.length ? "" : String.valueOf(arr[bigger])),
target);
}
输出
[1, 1, 3, 4, 4, 6]
| Index | Value |
| < <= ~ >= > | < <= ~ >= > |
--+----------------------+---------------------+
0 | -1 -1 0 0 0 | 1 1 1 | 0
1 | -1 1 0 0 2 | 1 1 1 3 | 1
2 | 1 1 1 2 2 | 1 1 1 3 3 | 2
3 | 1 2 2 2 3 | 1 3 3 3 4 | 3
4 | 2 4 3 3 5 | 3 4 4 4 6 | 4
5 | 4 4 4 5 5 | 4 4 4 6 6 | 5
6 | 4 5 5 5 6 | 4 6 6 6 | 6
7 | 5 5 5 6 6 | 6 6 6 | 7