在排序数组中,您可以使用二进制搜索来执行许多不同类型的操作:
你可以在堆栈溢出中找到#2和#5的答案,答案是使用二进制搜索的突变,但是没有固定的算法来回答这些问题,特别是在调整索引时。
例如,在问题3中,找到排序数组中第一个小于或等于元素的元素:
给定int[] stocks = new int[]{1, 4, 3, 1, 4, 6};
,我想找到小于5的第一个元素。它应该在排序后返回4,我的代码如下:
private static int findMin(int[] arr, int target) {
Arrays.sort(arr);
int lo = 0;
int hi = arr.length - 1;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (arr[mid] == target) return mid;
if (arr[mid] > target) {
hi = mid - 1;
} else {
lo = mid;
}
}
return lo;
}
这里的逻辑是:
如果你运行它,它实际上进入了一个无限循环,但只是将hi = arr.length - 1
的起始索引调整为hi = arr.length;
,它实际上运行良好。我不知道如何真正设置所有条件:如何编写条件,如何设置hi和lo的起始索引并使用lo<=hi
或lo < hi
。
任何帮助?
答案 0 :(得分:0)
基本上在上面提到的情况下,你需要一个小于给定值的最大元素,即你需要找到给定元素的底面。 这可以使用O(logn)中的二进制搜索,时间:
轻松完成您需要考虑的案例如下:
如果最后一个元素小于x,则返回最后一个元素。
如果中间点是楼层,则返回中间位置。
尝试以下方法:
static int floorInArray(int arr[], int low, int high, int x)
{
if (low > high)
return -1;
// If last element is smaller than x
if (x >= arr[high])
return high;
// Find the middle point
int mid = (low+high)/2;
// If middle point is floor.
if (arr[mid] == x)
return mid;
// If x lies between mid-1 and mid
if (mid > 0 && arr[mid-1] <= x && x < arr[mid])
return mid-1;
// If x is smaller than mid, floor
// must be in left half.
if (x < arr[mid])
return floorInArray(arr, low, mid - 1, x);
// If mid-1 is not floor and x is
// greater than arr[mid],
return floorInArray(arr, mid + 1, high,x);
}
答案 1 :(得分:0)
在您的while循环中,您没有为hi == lo
当您迭代最后一个元素或数组只有一个元素时,这种情况适用。
将while循环设置为while(lo <= hi)
,并在搜索所有元素时终止
或者在hi
等于lo
时设置if case内循环。
if(hi == lo)
答案 2 :(得分:0)
您可以只使用Arrays.binarySearch(int[] a, int key)
,而不是实现自己的二分查找,然后相应地调整返回值。
返回搜索键的索引(如果它包含在数组中);否则,( - (插入点) - 1)。 插入点定义为将键插入数组的点:第一个元素的索引大于键,如果数组中的所有元素都小于,则为a.length指定的密钥。请注意,当且仅当找到密钥时,这可以保证返回值>> =。
当有多个有效选择时,您的规则没有指定要返回的索引(#3或#4具有多个相等的值,或者#5具有等距值),因此下面的代码具有明确选择的代码。如果您不关心歧义,可以删除额外的代码,如果您不同意我的决定,则可以更改逻辑。
请注意,当返回值为&lt; 0时,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
答案 3 :(得分:0)
尝试树集。如果您输入的是数组,请执行以下步骤: