小编典典

O(log n)算法在排序数组中找到最佳插入位置

algorithm

我正在尝试寻找一种找到最佳位置的算法,以将 目标 插入已排序的数组中。

目标是要么返回该项目在列表中的位置,要么返回将其保持列表排序的位置。

所以说我有一个清单:

   0   1   2   3   4    5    6
 ---------------------------------
 | 1 | 2 | 4 | 9 | 10 | 39 | 100 |
 ---------------------------------

我的目标项目是14 它应该返回一个索引位置5

我目前拥有的伪代码:

array = generateSomeArrayOfOrderedNumbers()

number findBestIndex(target, start, end)
    mid = abs(end - start) / 2

    if (mid < 2) 
        // Not really sure what to put here
        return start + 1 // ??

    if (target < array[mid])
        // The target belongs on the left side of our list //
        return findBestIndex(target, start, mid - 1)
    else
        // The target belongs on the right side of our list //
        return findBestIndex(target, mid + 1, end)

我不太确定现在要写些什么。我试图对此采取二进制搜索方法,但这是在5次重写左右之后我能想到的最好方法。


阅读 246

收藏
2020-07-28

共1个答案

小编典典

您的代码有几个问题:

mid = abs(end - start) / 2

这是 不是 之间的中间startend,这是他们之间的距离的一半(四舍五入到整数)。后来,您将其用作确实是有效的索引:

findBestIndex(target, start, mid - 1)

不是。您可能打算在mid = (start + end) // 2这里使用或其他东西。您还会错过一些索引,因为您跳过了中间部分:

return findBestIndex(target, start, mid - 1)
 ...
return findBestIndex(target, mid + 1, end)

现在,您的基本情况也必须有所不同。一个好的候选人是条件

if start == end

因为现在您肯定知道您已经完成搜索。请注意,您还应该考虑所有数组元素都小于的情况target,因此您需要在最后插入它。

我不经常搜索二进制文件,但是如果我这样做,这就是

如果您从未尝试过二进制搜索,那么很难正确地进行二进制搜索。如果执行二进制搜索,通常会使用以下模式:

lo, hi = 0, n // [lo, hi] is the search range, but hi will never be inspected.
while lo < hi:
    mid = (lo + hi) // 2
    if check(mid): hi = mid
    else:          lo = mid + 1

在该条件check是一个单调二元谓词(它始终是false直到某个点和true从该点),该循环后,lo == hi将在范围内的第一个数字[0..n]check(lo) == truecheck(n)隐式地假定它是正确的(这是此方法的魔力的一部分)。

那么,true对于包括我们目标false位置前后的所有索引以及之前目标位置的所有索引而言,单调谓词是什么?

如果我们考虑一下,我们想在数组中找到比目标大的第一个数字,因此我们只需要插入它就可以了:

lo, hi = 0, n
while lo < hi:
    mid = (lo + hi) // 2
    if (a[mid] > target): hi = mid
    else:                 lo = mid + 1
return lo;
2020-07-28