在进行竞争性编码时,我遇到了一个需要删除O(log n),同时能够为二进制搜索支持索引(最好是O(1))的情况。我本质上需要使用二进制方法(当前使用bisect)来定位元素,然后删除我发现的该元素,该元素当前是O(n)操作。我显然不能使用未内置的库,因此为什么blist不是选项,并且我不能使用集合,因为它不支持索引。是否有替代方法,还是仅使用二叉树之类的方法。如果是这样,我可以在python中使用任何简单的预定义库吗?
答案 0 :(得分:0)
Python在标准库中似乎没有这样的结构。
我不确定您的需求,但是由于您考虑使用一套,因此您不需要重复的物品。考虑不更改删除列表的长度。而是将您要删除的元素替换为右侧的第二高(非相等)邻居。 (如果恰好是最后一个元素,则可以将其弹出。)长度和常规索引将是错误的,但是二进制搜索仍将起作用,这可能就是您需要为其建立索引的全部条件。
假设您有[0,1,2,3,4,5]
,并且想要删除3
。列出列表[0,1,2,4,4,5]
。然后,如果要删除4
,请使其[0,1,2,5,5,5]
。
您可以使用二进制搜索找到运行的两端,这为您提供了所需的O(log n)去除。首先使用bisect_left
,然后输入答案以限制bisect_right
搜索的列表部分。知道界限后,Python可以立即分配整个切片。
如果您随后要删除5
,请将其弹出[0,1,2]
。列表末尾的删除效率更高,因为它不需要分配新的数组。
您可以偶尔清理重复项,以获得更好的摊销性能,或者如果您需要长度或其他内容。也许当“删除”的数量达到原始长度的一定比例时。不要经过set
,因为您必须重新排序。 (OrderedDict.fromkeys
可以工作,但是您仍然必须从.keys()
建立一个列表)。只需复制列表,同时跳过重复项即可,例如
itr = iter(old)
new = [next(itr)]
for e in itr:
if e is not new[-1]:
new.append(e)