【问题标题】:Dynamic Programming/Memoization (counting triplets)动态编程/记忆(计数三元组)
【发布时间】:2012-04-13 19:51:15
【问题描述】:

我有一个这样的数字列表(随机生成,数字在每个子组中排序。这些组是不相交的,这意味着您不会在多个组中找到给定的数字):

L=[[19,18,14,9,4],[15,12,11,10,6,5],[8],[16,13,3,2],[17,7,1]]

我正在尝试计算可以创建递减三元组的方法的数量。

递减三元组是一个三元组,我们从左到右扫描列表并从一组中取出元素 1,然后从另一组中取出元素 2,然后从另一组中取出元素 3,其中最终结果应按降序排列自然。

例如,(19,11,7) 是一个有效的递减三元组,因为这些数字来自不同的子列表并且按照递减的自然顺序(主列表中的 19 在 11 之前,在 7 之前)。

用一个反例来澄清一下:(15, 9, 8) 不会是一个递减的三元组,因为 9 来自比 15 更早的子列表。

我正在尝试使用动态编程或某种形式的记忆来计算递减三元组的数量。像这样设置循环结构很容易:

for i in xrange(0,len(L)-2):
    for j in xrange(i+1, len(L)-1):
        for k in xrange(j+1, len(L)):
            for item1 in L[i]:
                for item2 in L[j]:
                    if item1>item2:
                        for item3 in L[k]:
                            if item2>item3:
                                count+=1

但它不能很好地扩展到更大的列表。我觉得应该有一些方法可以通过遍历列表一次来计算三胞胎。例如,如果我知道一个数字大于另一个数字(或者如果我知道它大于多少个数字),我觉得我应该能够在以后重新使用该信息。

例如,我知道在有效的三元组中 16 可以出现在 7 或 1 之前。那是2个“对”。因此,如果我想在列表中倒退时创建一个三元组,例如,我查看 19,我应该能够说“它大于 16,因此您可以从中创建两个三元组,因为我们知道16 大于 2 个数字。”等等。

我只是在大声思考,但希望能得到一些见解。

【问题讨论】:

  • 您的“组”列表中的每一个是否都是不相交的整数集?
  • 是的;没有数字会出现在一个以上的组中。将编辑澄清。

标签: c++ python dynamic-programming memoization


【解决方案1】:

0n 之间使用索引i 而不是嵌套循环。 跟踪当前三元组的最后一个元素。 并使用备忘录使其高效。

L=[[19,18,14,9,4],[15,12,11,10,6,5],[8],[16,13,3,2],[17,7,1]]

n=len(L)

memo = {}
def f(i,j,last):
  if (i,j,last) in memo:
    return memo[(i,j,last)]
  if j==3:
    return 1
  if i==n:
    return 0
  res=0
  # take one from L[i]
  for x in L[i]:
    if last > x:
      res+=f(i+1,j+1,x)
  # don't take any element from L[i]
  res += f(i+1,j,last)
  memo[(i,j,last)] = res
  return res

BIG = 10**9
print f(0,0,BIG)

【讨论】:

    【解决方案2】:

    试试下面的itertool解决方案

    import itertools
    import time
    
    L= [
        {19, 18, 14, 9, 4},
        {15, 12, 11, 10, 6, 5},
        {8},
        {16, 13, 3, 2},
        {17, 7, 1},
    ]
    
    
    start = time.time()
    for i in xrange(20000):
        count = 0
        for i in xrange(0,len(L)-2):
            for j in xrange(i+1, len(L)-1):
                for k in xrange(j+1, len(L)):
                    for item1 in L[i]:
                        for item2 in L[j]:
                            if item1>item2:
                                for item3 in L[k]:
                                    if item2>item3:
                                        count+=1
    
    print
    print time.time() - start
    
    # result: 3.1542930603
    
    start = time.time()
    for i in xrange(20000):
        sum(1 for l1, l2, l3 in itertools.combinations(L, 3) for a, b, c in itertools.product(l1, l2, l3) if a > b > c)
    
    print
    print time.time() - start
    
    # result: 1.94973897934
    

    【讨论】:

    • 我只是想计算它们,而不是枚举它们或实际上知道三元组是什么。
    • @AOAOne:如果你想计算它们,只需在列表中添加一个长度
    • 虽然这确实有效,但它比我上面列出的当前方法要慢。
    • 是的,我只跑了 20000 次,3.15921497345 vs 4.37073898315
    • 对于更大的列表:5.54514414542 与 131.797990247
    猜你喜欢
    • 1970-01-01
    • 2023-03-05
    • 2013-05-11
    • 1970-01-01
    • 2021-10-01
    • 2020-12-10
    • 2010-10-15
    • 2011-09-05
    相关资源
    最近更新 更多