我有一个家庭作业问题,要编写一个函数,该函数是bagOfWords类的一部分,以从未排序的列表中删除值的实例。我们可以使用的列表操作不包括remove()。我们只需要具有O(n)复杂度,而朴素的算法就不能很好地完成这一工作。
我尝试了一个幼稚的算法。这太复杂了。它使用list.pop(index)本身具有O(n)复杂度,并且具有两个循环。由于不允许使用list.remove(),并且由于列表理解将具有相同的复杂性,但语法更加简洁,因此我试图找到一种更好的实现。
我认为也许解决方案是一种快速排序算法,因为如果我首先对列表进行排序,我可能能够以O(n)的复杂性来做到这一点。但是,如何在没有pop(index)复杂性的情况下删除该项目?现在我想知道通过KMP算法搜索模式是解决方案还是散列。
def remove(self, item):
"""Remove all copies of item from the bag.
Do nothing if the item doesn't occur in the bag.
"""
index = 0
while index < len(self.items):
if self.items[index] == item:
self.items.pop(index)
else:
index += 1
复杂度是二次的。但是,我想要的复杂度是O(n)
编辑:为澄清起见,我们实际上仅限于修改现有列表。
答案 0 :(得分:3)
编辑:最简单(也可以说是“正确”)的方法是使用列表理解:
self.items = [x for x in self.items if x != item]
它是O(n),并且比以下选项更快。到目前为止,它也是最“ pythonic”的。
但是,它确实创建了列表的新副本。如果您实际上不得不修改现有列表,这是我的原始答案:
这是一种“就地” O(n)算法,该算法使用两个指针将列表折叠起来,从而删除了不需要的元素:
ixDst = 0 for ixSrc in range(0, len(items)): if items[ixSrc] != item: items[ixDst] = items[ixSrc] ixDst += 1 del items[ixDst:]
(看到它运行here)
唯一可疑的部分是使用
del
缩小列表的大小。我相信它就位,并且“应该”为O(1),因为我们要删除的切片位于列表的末尾。
此外,@ chepner在评论中建议使用更Python化的就地答案(且速度更快):
self.items[:] = (x for x in self.items if x != item)
感谢@ juanpa.arrivillaga和@chepner的讨论。
答案 1 :(得分:0)
如果列表中的元素是相对较小的整数,或者可以这样表示,则可以使用O(max(maxValue,n))进行排序。
另一种方法是为列表中的每个元素提供指向上一个和下一个元素的指针。这样,您可以删除O(1)中的一个元素。但是,这使按索引获取项目的操作在O(n)时间内运行。
如果项目的顺序无关紧要,您可以存储(item, count)
之类的对,其中count
是出现item
的次数,那么您只需删除一对这样的对给定item
并具有所需的复杂性。
希望有帮助!
答案 2 :(得分:0)
如果需要它来执行就地删除,则可以将项目移到要删除的项目上,并在最后一次操作中截断列表:
index = 0
for value in self.items:
if value != item :
self.items[index] = value
index += 1
del self.items[index:]
如果您有能力创建新列表(无需列表理解),则可以这样做:
cleanedItems = []
for value in items:
if value != item: cleanedItems.append(value)
self.items = cleanedItems