检查列表中的组合数量,您可以创建三角形

时间:2018-03-20 14:57:44

标签: python list

我正在编写一个Python程序,它返回列表中可以创建三角形的组合数。

示例:

--> test([1,1,3])
0 #you cant make a triangle out of 1,1,3 (the only combination in this list)

--> test([2,789,5,3,3237,4])
3 #you can make a triangle out of [2,5,4],[5,3,4] and [2,4,3]

我只设法编写一个函数来检查你是否可以在3个给定边中创建一个三角形:

def check(a,b,c):
    n = max((a,b,c))
    x = 0
    y = 0
    for i in [a,b,c]:
        if i != n:
            if x == 0:
                x = i
            elif y == 0:
                y = i 
    return (x+y)>n

2 个答案:

答案 0 :(得分:0)

使用函数来检查是否有任何三个边可以在评论中给出三角形check非常容易:

from itertools import combinations

def test(x):
    return sum(check(*comb) for comb in combinations(x, 3))

这使用itertools.combinations提供所有可能的组合的事实,此处输入的长度为3,以及bool为True == 1False == 0的整数,所以我们可以将它们相加以获得True元素的数量。

您的check功能也可能更明确:

def check(a, b, c):
    a, b, c = sorted([a, b, c])
    return a + b > c

答案 1 :(得分:0)

首先,您的检查功能不正确。从this post,我们看到所需的条件是每对边的总和大于另一边。正如@david explained

  

假设a,b,c是三角形的边。因此,它   必须满足这个标准:

     
      
  1. a + b> ç
  2.   
  3. a + c> B'/ LI>   
  4. b + c>一个
  5.   

您只是检查两个较小边的总和是否大于最大值。此外,对于最大边重复的情况,您的功能将失败。例如,值1, 4, 4形成有效三角形,但您的函数check(1, 4, 4)返回False

话虽如此,你几乎无法避免检查3个值的所有组合。

from itertools import combinations
[(x, y, z) for (x, y, z) in combinations(test, 3) 
 if ((x+y) > z) and ((x+z) > y) and ((y+z) > x)]
#[(2, 5, 4), (2, 3, 4), (5, 3, 4)]

您可以通过对列表进行排序来提高边际速度。这有帮助,因为代码可能会短路,因为第一个条件会失败(而且你不必检查另外两个)。

例如,这些是示例列表中3个边的排序组合:

>>> test = [2,789,5,3,3237,4]
>>> list(combinations(sorted(test), 3))
[(2, 3, 4),
 (2, 3, 5),
 (2, 3, 789),
 (2, 3, 3237),
 (2, 4, 5),
 (2, 4, 789),
 (2, 4, 3237),
 (2, 5, 789),
 (2, 5, 3237),
 (2, 789, 3237),
 (3, 4, 5),
 (3, 4, 789),
 (3, 4, 3237),
 (3, 5, 789),
 (3, 5, 3237),
 (3, 789, 3237),
 (4, 5, 789),
 (4, 5, 3237),
 (4, 789, 3237),
 (5, 789, 3237)]

在第三个示例中,x = 2y = 3z = 789。第一个条件(x+y) > z将失败,您不必检查其他两个条件。我已经包含了一些时序结果,以显示排序稍微更快。

更新

如果您想避免重复,可以使用集合理解:

{(x, y, z) for (x, y, z) in combinations(sorted(test), 3) if 
 ((x+y) > z) and ((x+z) > y) and ((y+z) > x)}

时间安排

# make list of random numbers
import numpy as np
N = 100
test = [np.random.randint(0,5000) for i in range(N)]

# without sorting
%%timeit
[(x, y, z) for (x, y, z) in combinations(test, 3) 
 if ((x+y) > z) and ((x+z) > y) and ((y+z) > x)]
#10 loops, best of 3: 76.1 ms per loop

# with sorting
%%timeit
[(x, y, z) for (x, y, z) in combinations(sorted(test), 3) if 
 ((x+y) > z) and ((x+z) > y) and ((y+z) > x)]
#10 loops, best of 3: 65.1 ms per loop