假设我有一个数组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)解决方案很简单,我希望能有更快的速度。 可能是二进制搜索,但不知道如何修改它。
答案 0 :(得分:2)
这是一个略微修改的二进制搜索,用于在返回之前与之前的元素进行比较。如果存在重复,则按预期继续二进制搜索,而不是串行搜索,因此它对于排序数组的结构独立地为O(log(n))(例如,当存在多个重复项时)。它是用Java编写的。
*如果元素不存在,我返回下一个更大元素的索引,即如果必须将其放入数组中,则应插入密钥的索引。我返回一个负值作为“未找到”的指标。
* 否定未找到值的唯一例外是当键是最小且未找到时,您期望0(它没有负数)。但是,您可以轻松处理这种特殊情况,以区分发现和未找到:例如,如果Integer.MIN_VALUE
则返回-(array.length + 1)
或-lo == 0
。
*如果键大于每个数组值,您希望返回一个等于数组大小的索引(再次为负值)。
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;
}
答案 1 :(得分:1)
标准二分查询:
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
这将使目标或该点的最左侧发生率为零 如果失踪,目标会去哪里。然后只是环顾四周 区域,看看要返回什么。
答案 2 :(得分:1)
以下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)]