【问题标题】:Find number of subset that satisfy these two conditions?找到满足这两个条件的子集数?
【发布时间】:2020-01-15 10:36:18
【问题描述】:
def findNumber(N,A,B):
    return count

Count 是数组子集的总数 - [1,2,3,...,N] 满足这些条件:

1.所有子集都应该是连续的。

2。任何子集都不应包含 A[i] 和 B[i](顺序无关紧要)。

例子

N = 3,A=[2,1,3],B=[3,3,1]

所有子集 = [1],[2],[3],[1,2],[2,3],[1,2,3]

无效的子集 = [2,3] 因为 A[0] 和 B[0] 在其中。 [1,2,3] 因为它包含 A[1],B[1] 和 A[2],B[2]

所以计数将是 4。

我能够计算出连续子集的总数将是 N(N+1)/2,但我被困在如何满足条件 2 上。

我已尽力解释它,如果需要,请要求澄清。

编辑

def findallvalid(n,a,b):
    for w in range(1, n+1):
        for i in range(n-w+1):
            if not((a[0],b[0]) in (i+1,i+w+1)):
                yield range(i+1,i+w+1)

我尝试了这段代码,但我不知道如何迭代 a 和 b 的所有值而不会使它变得非常慢。它已经在 n>10^2 时变慢了。

1

【问题讨论】:

  • 请用您已有的代码更新问题。
  • 当你说“不子集应该包含A[i]B[i]”时,你的意思是只有当A[i] B[i]时子集才无效在那个子集中,对于相同的i?
  • @00 是的,这是唯一的条件,除了子集是连续的。
  • @CosminStaicu 我将我的代码添加到问题中。
  • A 和 B 的最大或典型长度是多少?

标签: python arrays algorithm


【解决方案1】:

我对如何在不生成子集的情况下解决此问题感兴趣,例如,我发现总连续子集将是 n(n+1)/2 我只想知道如何知道要排除的子集数量。

这给了我一个想法——确实,计算被一对(A[i],B[i])排除的子集的数量非常简单。对多对来说更具挑战性,因为排除的子集可以重叠,所以只为每对减去一个数字是行不通的。有效的是拥有一组所有 N(N+1)/2 个子集的数字或索引,并从中删除排除子集的索引;最后,缩减索引集的基数是剩余子集的所需数量。

def findNumber(N, A, B):
    count = N*(N+1)//2
    powerset = set(range(count))    # set of enumeration of possible intervals
    for a, b in zip(A, B):
        if a > b: a, b = b, a       # let a be the lower number
        # when a and b are in a subset, they form a sub-subset of length "span"
        span = (b-a)+1
        start = 0       # index where the invervals of current length w begin
        for w in range(1, N+1):     # for all interval lengths w
            if span <= w:           # if a and b can be in interval of length w
                first = 0 if b <= w else b-w    # index of first containment
                last = a                        # index of last containment
                # remove the intervals containing a and b from the enumeration
                powerset -= set(range(start+first, start+last))
            start += N+1-w          # compute start index of next length w
    return len(powerset)            # number of remaining intervals

【讨论】:

    【解决方案2】:

    我对你的代码做了一些小的修改, 这段代码真的很慢,因为它正在迭代整个列表,它可以由 10^5 个项目组成,并且做一些嵌套操作会使复杂度飙升到 10^10,这真的很慢

    from collections import defaultdict
    
    def findallvalid(N,A,B):
      a_in = defaultdict(list)
      b_in = defaultdict(list)
    
      for idx, a in enumerate(A):
        a_in[a].append(idx)
      for idx, b in enumerate(B):
        b_in[b].append(idx)
    
      def diff_elem_index(subset):
        indecies = []
        for elem in subset:
          indecies.extend(a_in[elem])
          indecies.extend(b_in[elem])
        return len(set(indecies)) == len(indecies)
    
      for set_window in range(1, N+1):
          for start_idx in range(N - set_window + 1):
            sett = list(range(start_idx+1,start_idx + set_window + 1))
            if diff_elem_index(sett):
              yield sett  
    

    我最接近的假设,因为代码只需要返回项目数 它可以用数学方法解决

    N 大小列表的所有传染性排列都是(N*(N+1))/2 + 1 之后您需要扣除不符合第二个条件的可能排列的计数,这可以从列表AB中算出

    我认为从列表 AB 中计算排除排列的计数将比遍历从 1 到 N 的所有排列更有效。

    【讨论】:

    • 我尝试了您的解决方案,并对其进行了修改,因此它只返回计数。但它仍然超过了 10 秒的时间限制。可以解释我如何找到要排除的集合数。
    猜你喜欢
    • 2012-01-22
    • 1970-01-01
    • 2013-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-14
    • 1970-01-01
    相关资源
    最近更新 更多