查找数组中指定元素的第一次出现

Find first occurence of specified element in an array

假设我有一个非降序数组 A 这样

A = [0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 4, 4, 4, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, 500, 600]

我的问题是:如何找到等于或大于(如果 4 不存在)大于 4 的元素的第一次出现(索引)?

O(n) 解决方案很简单,我想要更快的东西。 可能是二分查找,但是不知道怎么修改。

标准二分查找:

left limit = left end of array
right limit = right end of array
look at middle
if middle == target: stop
else:
    set left or right to middle based on result of comparison
    loop

此变体,更改标记为 *

left limit = left end of array
right limit = right end of array
look at middle
* if limits are close together: stop
* if middle == target and limits are not close together:
*    set right to middle
*    loop
else:
    set left or right to middle based on result of comparison
    loop

这会将目标最左侧的发生率或点归零 如果目标丢失了,它会去哪里。然后环顾四周 区看看有什么要return.

以下 python 代码使用简单的二进制搜索算法来查找上限值。运行时间 O(log(n))

def binary_search(array, target):
lower = 0
upper = len(array)
while lower < upper:
    x = lower + (upper - lower) // 2
    val = array[x]
    if target == val:
        return x
    elif target > val:
        if lower == x:
            break
        lower = x
    elif target < val:
        upper = x
return upper

# Test Array
arr = [0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 4, 4, 4, 5, 4, 4, 6, 7, 8]
print arr[binary_search(arr, 5)]

这是一个稍微修改过的二进制搜索,用于与 returning 之前的前一个元素进行比较。如果有重复项,您将按预期继续二进制搜索,而不是串行搜索,因此它的 O(log(n)) 独立于排序数组的结构(例如,当存在许多重复项时)。它写在 Java.

*如果该元素不存在,我 return 下一个更大元素的索引,即如果我必须将它放入数组中,则应插入键的索引。我return一个负值作为"not found"的指标。

*negative not-found value 的唯一例外是当键最小且 not-found 时,您期望 0(它不是有负数)。但是,您可以轻松处理这种特殊情况以区分 found 和 not-found:例如 return Integer.MIN_VALUE-(array.length + 1) if -lo == 0.

*如果键大于每个 array-value,您期望 return 索引等于数组大小(再次为负值)。

public static int indexOf(int[] a, int key) {
    int lo = 0;
    int hi = a.length - 1;
    while (lo <= hi) {
        int mid = lo + (hi - lo) / 2;
        if      (key < a[mid]) hi = mid - 1;
        else if (key > a[mid]) lo = mid + 1;
        else if (mid == 0 || key != a[mid-1]) return mid;
        else hi = mid - 1; //we have a duplicate, go left
    }
    //not present; show index of next greater element
    //OR array.length if bigger than every existing element
    return -lo;
}