[英]Finding Missing Element in an Array
我有一个有趣的问题,给出了两个排序的数组:
a有n个元素,b有n-1个元素。
b除了一个元素之外的所有元素都缺失了。
如何在O(log n)时间内找到该元素?
我试过这段代码:
def lostElements2(a, b):
if len(a)<len(b):
a, b = b, a
l, r = 0, len(a)-1
while l<r:
m = l + (r-l)//2
if a[m]==b[m]:
l = m+1
else:
r = m - 1
return a[r]
print(lostElements2([-1,0,4,5,7,9], [-1,0,4,5,9]))
我不知道我应该在函数中返回什么,如果它是[l],[r]?
我得知函数内部的逻辑应该如何:如果两个数组的中间值匹配,则意味着,b直到中点与a相同,因此缺少的元素必须在mid的右边。
但我无法创建最终解决方案,何时应该停止循环以及应该返回什么? 它如何保证[l]或[r]确实是缺失的元素?
这个问题的原理很简单,细节很难。
你已经安排了数组a
是更长的数组。 好,这简化了生活。 现在你需要返回的值, a
在第一位置的值a
从的值不同b
。
现在您需要确保处理以下边缘情况。
a
具有值的位置)。 a = [1, 1, 2, 2, 2, 2, 3]
而b = [1, 2, 2, 2, 2, 3]
- 当你在中间着陆时,值匹配的事实会误导您! 祝好运!
l
和r
的点应该是l
始终是列表相等的位置,而r
总是它们不同的位置。 IE浏览器。 a[l]==b[l]
和a[r]!=b[r]
代码中唯一的错误是将r
更新为m-1
而不是m
。 如果我们知道a[m]!=b[m]
,我们可以安全地设置r=m
。 但将其设置为m-1
可能会a[r]==b[r]
,这会破坏算法。
def lostElements2(a, b):
if len(a) < len(b):
a, b = b, a
if a[0] != b[0]:
return a[0]
l, r = 0, len(a)-1
while l < r:
m = l + (r-l)//2
if a[m] == b[m]:
l = m+1
else:
r = m # The only change
return a[r]
(正如@btilly所指出的,如果我们允许重复的值,这个算法会失败。)
从@btilly编辑
为了解决这个潜在的缺陷,如果值相等,我们搜索具有相同值的范围。 为此,我们以1号,2号,4号,8号等步长向前走,直到值切换,然后进行二分查找。 并向后走同样的道路。 现在寻找每个边缘的差异。
该搜索所需的努力是O(log(k))
,其中k
是重复值的长度。 所以我们现在用搜索替换O(log(n))
查找。 如果在该搜索的长度上存在上限K
,则表示总运行时间。 O(log(n)log(K))
。 这使得最坏情况下的运行时间为O(log(n)^2)
。 如果K
接近sqrt(n)
,那么实际上很容易碰到最坏的情况。
我在评论中声称,如果最多K
元素重复超过K
次,则运行时间为O(log(n)log(K))
。 进一步分析,这种说法是错误的。 如果K = log(n)
并且log(n)
运行长度sqrt(n)
被放置以命中搜索的所有选择,那么你得到运行时间O(log(n)^2)
而不是O(log(n)log(log(n)))
。
但是,如果最多log(K)
元素重复超过K
次,那么你得到的运行时间为O(log(n)log(K))
。 对于大多数情况来说,哪个应该足够好。 :-)
您的代码不处理缺少元素是索引m本身的情况。 后面的if / else子句将始终移动缺少元素的边界,使其不包括m。
您可以通过添加额外的检查来解决此问题:
if a[m]==b[m]:
l = m+1
elif m==0 or a[m-1]==b[m-1]:
return a[m]
else:
r = m - 1
另一种方法是存储m的最后一个值:
last_m = 0
...
else:
last_m = m
r = m - 1
...
return a[last_m]
哪会导致它在上次检测到不匹配时返回。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.