【问题标题】:Intersection of two list in N timeN时间两个列表的交集
【发布时间】:2015-01-06 21:10:00
【问题描述】:

我有两个列表(['a', 's', 'f', 'f', 's'], ['f', 'f', 'a', 's'])。所需的输出是['a','s','f','f']。输出应该给出两个列表的交集。输出列表中的字符排列是按照第一个列表['a', 's', 'f', 'f', 's']中出现的顺序。

如何在 python 中实现它?我已经在 N ** 2 次中完成了此操作。是否有可能在 N 时间内做到这一点?
我目前的解决方案:

def com(字符串 1,字符串 2): string2_list=list(string2) 商店="" 签入string1: 对于枚举(string2_list)中的 i,v: 如果 v== 检查: 商店=商店+检查 德尔(string2_list[i]) 退货商店

【问题讨论】:

  • 那么您目前的解决方案是什么?
  • 因为骗子不关心O(N),这似乎是这个问题的关键部分
  • 老实说,我认为你不能低于 O(NlogN)。我们会看到答案
  • 这不是链接问题的副本。这种情况包括订购,另一种不包括。
  • 创建计数器是 O(N) 每个(你需要迭代每个列表),集合交集与常量集合查找是线性的,所以你最多得到 3*N。

标签: python algorithm


【解决方案1】:

使用collections.Counter的内置交集运算。

>>> l1, l2 = (['a', 's', 'f', 'f', 's'], ['f', 'f', 'a', 's'])
>>> import collections
>>> collections.Counter(l1) & collections.Counter(l2)
Counter({'f': 2, 'a': 1, 's': 1})

从这里开始建立一个合适的列表并不难:

>>> counter = collections.Counter(l1) & collections.Counter(l2)
>>> out = list(counter.elements())
>>> print out
['a', 's', 'f', 'f']

或者,根据列表之一订购:

>>> out = []
>>> for k in l1:
...     if counter[k] > 0:
...         counter[k] -= 1
...         out.append(k)
...
>>> print out
['a', 's', 'f', 'f']

这是预期时间 O(N):创建计数器需要 O(N) 时间,计数器交集也需要 O(N) 时间。 ​

【讨论】:

  • 最后一个例子中的counter不应该只是Counter(l2)而不是总和吗?
  • Sice 计数器是一个无序集合,构建有序列表不应该取 theta(NlogN) 吗?
  • @wim:这实际上并不重要,真的。我这样做是因为感觉更正确。
  • @BlackBear:我们根据l1中的排序构建有序列表,它已经按照我们想要的方式排序。所以这里没有“log n”惩罚。
  • hmm,柜台上的& 是交集(min(counter1[k], counter2[k]),我认为这里不合适
【解决方案2】:

这可以使用集合中的计数器:

import collections

a = ['a', 's', 'f', 'f', 's']
b = collections.Counter(['f', 'f', 'a', 's'])

output = []
for x in a:
    if b.get(x):
        output.append(x)
        b.subtract(x)

print output

结果:

['a', 's', 'f', 'f']

这里的算法复杂性不是 100% 确定的,但我的猜测是计数器内的查找是 O(1)(基于散列),这使得 O(n)

【讨论】:

  • 谁能解释一下这里的-1?
【解决方案3】:

这会创建一个字典来查找 l1 项的顺序而不是 l1 的索引方法:

>>> from collections import Counter
>>> l1, l2 = (['a', 's', 'f', 'f', 's'], ['f', 'f', 'a', 's'])
>>> l1_to_index = {val: indx for indx, val in reversed(list(enumerate(l1)))}
>>> sorted((Counter(l1) & Counter(l2)).elements(), key=lambda x: l1_to_index[x])
['a', 's', 'f', 'f']
>>> 

【讨论】:

    【解决方案4】:

    对列表进行排序,这将为您提供: 清单 1:“嘘” 清单 2:“affs”。 然后使用字符串匹配循环

    伪代码(可能需要稍作调整)

    list1;
    list2;
    list3; //output list
    n = list1.length() //list1 length
    x = list2.length() //list2 length
    int i = 0; //list1 counter
    int j = 0; //list2 counter
    //go through both list simutainously and remove the lexographically smallest at every list1[i] != list2[j]
    while i != n and j != x
        if list1[i] == list[j]
            list3.add(list1(i))
            i++
            j++
        else
            if list1[i]<=list[j]
                i++;
            else
                j++
    return list3
    

    算法成本: 排序 = O(nlgn) 轻松使用合并排序,或者如果您可以使用随机快速排序,快速排序通常会快 3 倍,如果不是:http://randalgos.blogspot.dk/2012/03/randomized-quick-sort-in-python.html while 循环最多需要 2n 次,给你留下:

    O(nlgn) + 2n = O(nlgn)

    【讨论】:

      猜你喜欢
      • 2021-03-18
      • 2013-10-07
      • 1970-01-01
      • 2013-08-29
      • 1970-01-01
      • 2011-02-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多