当working on an AoC puzzle时,我发现我想减去列表(保留排序):
def bag_sub(list_big, sublist):
result = list_big[:]
for n in sublist:
result.remove(n)
return result
我不喜欢list.remove
调用(它本身就是O(n))包含在循环中的方式,这似乎是不必要的低效率。所以我试着重写它以避免这种情况:
def bag_sub(list_big, sublist):
c = Counter(sublist)
result = []
for k in list_big:
if k in c:
c -= Counter({k: 1})
else:
result.append(k)
return result
现在这是O(n),还是Counter.__isub__
用法仍然搞砸了?
这种方法要求元素必须是可清除的,这是原始文件没有的限制。是否有O(n)解决方案,避免产生这种额外的限制? Python有没有比collections.Counter
更好的“bag”数据类型?
您可以假设sublist
的长度是list_big
的一半。
答案 0 :(得分:3)
我使用了一个计数器,但我可能会略有不同,我可能会反复这样做......
def bag_sub(big_list, sublist):
sublist_counts = Counter(sublist)
result = []
for item in big_list:
if sublist_counts[item] > 0:
sublist_counts[item] -= 1
else:
result.append(item)
return result
这与你的解决方案非常相似,但每次你想减少某些东西的数量时,创建一个全新的计数器可能效率不高。 1
此外,如果您不需要返回列表,请考虑生成器函数...
只要list_big
和sublist
中的所有元素都可以进行哈希处理,就可以正常工作。此解决方案为O(N + M)
,其中N
和M
分别是list_big
和sublist
的长度。
如果元素无法进行哈希处理,除非您有其他约束(例如,使用相同的标准对输入进行排序),否则运气不佳。如果您的输入已排序,您可以执行类似于合并排序的合并阶段的操作,以确定bag_sub
中sublist
中的哪些元素。{/ p>
1 请注意,Counter
的行为与defaultdict(int)
的行为非常相似,因此在柜台中查找项目时完全没问题已经没有了。
答案 1 :(得分:2)
这现在是O(n),还是
Counter.__isub__
用法仍然搞砸了?
这是预期的情况O(n),除了当Counter.__isub__
丢弃非正值时,它会通过每个键来执行此操作。你最好只从键值减去1"通常"方式并检查c[k]
而不是k in c
。 c[k]
的{{1}}为0,因此您不需要进行k not in c
检查。)
in
是否有O(n)解决方案可避免产生此额外限制?
仅当输入已排序时,在这种情况下,mergesort merge的标准变体才能执行此操作。
Python有没有更好的" bag"数据类型比
if c[k]: c[k] -= 1 else: result.append(k)
?
collections.Counter
是Python的包。
答案 2 :(得分:-1)
所以我不知道如何把它降到O(N)。
写这篇文章的简明方法:
new_list = [x for x in list_big if x not in sublist]
但那仍然是O(kN)。