以下是二进制搜索的略微修改的实现,它找到第一次出现的Integer键。
这仍然是O(log n)吗?我在确定在最坏的情况下是否会成为O(n)时遇到一些麻烦。
private static Integer lowestRank(Integer[] a, Integer key) {
Integer lo = 0;
Integer hi = a.length - 1;
while (lo <= hi) {
Integer mid = lo + ((hi - lo) / 2);
if (key.compareTo(a[mid]) > 0) {
lo = mid + 1;
} else if (key.compareTo(a[mid]) < 0) {
hi = mid - 1;
// Modified here to return the first occurrence of the key, if it exists
} else if (lo < mid) {
hi = mid;
} else {
return mid;
}
}
return -1;
}
答案 0 :(得分:1)
是的,它仍然是O(log(n))
。第三个条件语句仅在key.compareTo(a[mid]) == 0
(因为前两个条件消除不等式情况)和lo < mid
时才运行。
如果密钥在数组中只存在一次,则此分支最多只发生一次;如果密钥不存在,则根本不会发生。由于条件本身以及条件体中的所有内容都是恒定时间操作,因此运行时间仍为O(log(n))
。
如果密钥多次出现怎么办?首先,无论如何,这个条件分支的目的是什么:
else if (lo < mid) {
hi = mid;
}
如果lo < mid
,则表示我们尚未扫描整个列表范围。因此,我们设置hi = mid
,从而将mid
设置为我们搜索的上限。
因此,即使密钥多次出现,搜索范围也会在每次迭代时减半。
答案 1 :(得分:1)
假设我们将单个语句建模为 O(1),那么我们的整体复杂性由循环迭代次数决定。
如果我们将范围([lo, hi)
)减少每次迭代的恒定量(平均),则迭代次数只能是 O(n)。在所有三个相关案例中,显然情况并非如此 - 平均范围总是减半。