算法 - 如何快速确保每个组的唯一元素

时间:2012-11-15 05:30:00

标签: python algorithm

不知道如何解释标题中的问题。

问题在于:

假设我们有4个小组:

(a, b, c, d)
(e, f)
(g, h, i)
(j, k, l, m, n)

现在我给了一个4元素元组,例如(a, e, h, m),两个都不是来自一个组,所以我返回True。如果给定(a, b, e, g),则a, b来自一个组,返回False。

然后这是我目前的想法,我给每个元素一个id开头的组号和测试重复。

g1 = ['1a', '1b', '1c', '1d']
g2 = ['2e', '2f']
g3 = ['3g', '3h', '3i']
g4 = ['4j', '4k', '4l', '4m', '4n']


def test(elements):
    if len(elements) != 4:
        return False

    stack = []
    for e in elements:
        mark = e[:1]
        if mark in stack:
            return False
        stack.append(mark)

    ga = set(g1 + g2 + g3 + g4)
    return set(elements).issubset(ga)


print test(('1a', '1b', '2e', '3g'))
print test(('1a', '2e', '3g', '4m'))

但我认为字符串比较不是一个非常优雅的解决方案,可以通过另一种更快的算法来完成吗?

2 个答案:

答案 0 :(得分:4)

如果所有元素都是可清除的,我会使用set.intersection

g1 = set(['1a', '1b', '1c', '1d'])
g2 = set(['2e', '2f'])
g3 = set(['3g', '3h', '3i'])
g4 = set(['4j', '4k', '4l', '4m', '4n'])

sets = [g1,g2,g3,g4]
test_this = ['1a','2e','3g','4j']

all(len(s.intersection(test_this)) <= 1 for s in sets)

或者,如果您不想更改g1,g2的类型......您可以更改test_this的类型:

g1 = ['1a', '1b', '1c', '1d']
g2 = ['2e', '2f']
g3 = ['3g', '3h', '3i']
g4 = ['4j', '4k', '4l', '4m', '4n']
lists = [g1,g2,g3,g4]
test_this = set(['1a','2e','3g','4j'])

all( len(test_this.intersection(lst)) <= 1 for lst in lists )

这里的美妙之处在于all足够聪明,可以短路 - 而且由于我们正在使用生成器表达式,因此我们不需要预先计算所有交叉点。只要所有先前的交叉点的长度小于或等于1,Python就只会继续计算交叉点。

答案 1 :(得分:2)

只是在解释器中玩,与mgilson一样,但是你不需要检查len(),现有的set()计算结果为True。

>>> g1 = ['1a', '1b', '1c', '1d']
>>> g2 = ['2e', '2f']
>>> g3 = ['3g', '3h', '3i']
>>> g4 = ['4j', '4k', '4l', '4m', '4n']
>>>
>>> groups = (g1, g2, g3, g4)
>>> t1 = ('1a', '1b', '2e', '3g')
>>> t2 = ('1a', '2e', '3g', '4m')
>>>
>>> all(set(t2).intersection(g) for g in groups)
True
>>> all(set(t1).intersection(g) for g in groups)
False
>>>