是否有任何方法可以在O(1)复杂度中从python中的列表中删除元素。即。 除去(值): 这会在列表中线性搜索并删除右键。 那么,有没有办法通过指定索引或值来删除O(1)复杂度中的元素?
当以下代码给出大小为100000的输入列表时,即使使用“del”,它也超过了时间限制。
l=map(int,raw_input("").split(" "))
n=l[0]
k=l[1]
s=map(int,raw_input("").split(" "))
s=sorted(s)
count=0
tree=[]
while len(s)>0:
poset=[]
indices=[]
i=0
poset.append(s[i])
indices.append(0)
j=i+1
while j<len(s):
if s[j]==k*s[i]:
poset.append(s[j])
indices.append(j)
i=j
j+=1
tmp=0
for i in indices:
del s[i-tmp]
tmp+=1
tree.append(poset)
for i in tree:
if len(i)%2==0:
count+=(len(i))/2
else:
count+=(len(i)+1)/2
print count
答案 0 :(得分:5)
正式没有。
如果您知道C ++ Python列表或多或少地实现为对象指针的std::vector
(在C语言中它们是指向连续指针数组的指针)。
这允许O(1)访问给定索引的元素并允许调整大小,但是从列表中删除元素需要将所有后续元素向下移动一个元素以填补空白。
但请注意,移动的内容只是指针,无需修复引用计数器即可完成,因此速度非常快(基本上只需一次memmov
调用)。除非列表很大,否则转移所需的时间非常短。
因此,如果使用del L[index]
知道索引,则从Python中的列表中删除元素正式为O(N)
,但具有很小的常数因子。
可以实现list
个对象,这样您就可以通过向列表对象添加“阶段”值来从任一端获取恒定时间。这将保持访问权限O(1)
(具有稍大的常量),但也允许del L[0]
O(1)
使其与deque
类似。
然而,这被认为是没有实现的,因为它会使list
访问对于正常情况更复杂,并针对具有特定结构deque
的特殊情况进行优化。它还会破坏与任何C扩展模块访问列表的兼容性。
答案 1 :(得分:2)
有没有办法通过指定索引或值来删除O(1)复杂度中的元素?
如果你知道索引是什么,那么
del L[index]
工作得非常快(但令人惊讶的是,不是O(1) - https://www.python.org/dev/peps/pep-3128/#motivation)。如果您只知道价值,那么它可能在任何地方,所以您必须搜索它。平均而言,它必须检查一半元素,因此这是O(N)。
其他数据结构可以提供帮助。如果您只想知道不同的元素是什么(并且不关心订单),您可以使用一套。
s = set(['1','b', '1', 'a', 1])
s
s.remove(1)
s
产出输出
{1, '1', 'a', 'b'}
{'1', 'a', 'b'}
和remove命令(基本上)是O(1)
答案 2 :(得分:0)
打开一个python终端(例如jupyer)并试试这个:
>>>: %%timeit
...: l = [i for i in range(10000000)]
...: del l[0] # O(?)
322 ms ± 1.68 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>>: %%timeit
...: l = list(range(10000000))
...: del l[0] # O(?)
195 ms ± 1.42 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>>: %%timeit
...: l = [i for i in range(10000000)]
...: del l[-1] # O(?)
306 ms ± 2.64 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>>>: %%timeit
...: l = list(range(10000000))
...: del l[-1] # O(?)
267 ms ± 2.68 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
>>>: %%timeit
...: l = [i for i in range(10000000)]
...: l.append(500) # O(1)
299 ms ± 3.28 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%%timeit
...: l = list(range(10000000))
...: l.append(500) # O(1)
265 ms ± 1.87 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
>>>: %%timeit
...: l = [i for i in range(10000000)]
...: max(l) # O(n)
463 ms ± 15.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>>: %%timeit
...: l = list(range(10000000))
...: max(l) # O(n)
335 ms ± 10.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>>: from collections import deque # lets compare with deque
>>>: %%timeit
...: l = deque(range(10000000))
...: max(l) # O(n)
365 ms ± 1.83 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>>: %%timeit
...: l = deque(range(10000000))
...: l.append(500) #O(1)
283 ms ± 5.19 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
>>>: %%timeit
...: l = deque(range(10000000))
...: del l[0]
279 ms ± 2.78 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
>>>: %%timeit
...: l = deque(range(10000000))
...: del l[9999999]
286 ms ± 3.87 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
如您所见,通过索引从双端队列中删除项目的复杂度为O(1),而从索引中删除列表则更加广泛,但与其他O(n)操作(如最大计算)相比仍然非常稳定。这与@ 6502答案一致。无论如何,如果你需要使用有向列表初始化器,差异非常小,因为时间由构造过程控制。通过调用实际构造函数的定向初始化是可取的。