【问题标题】:select k size subset by picking only one value from each set通过从每个集合中仅选择一个值来选择 k 个大小的子集
【发布时间】:2020-03-13 01:50:14
【问题描述】:

给定一个长度为 n 个元素的数组,其中每个元素表示集合大小,确定可以选择 K 大小集合的方式数。

条件:您不能从一组中选择多个元素。如何 解决这个问题(任何程序)

例子:

输入:

n = 4
k = 3
{1,2,1,1} Each value represents number of elements in each set

输出:7

Example : 

{1},{2,3},{4},{5}

{1,2,4}
{1,2,5}
{1,3,4}
{1,3,5}
{1,4,5}
{2,4,5}
{3,4,5}

我尝试过的代码,但它返回 10 个不符合条件的值 我在这里犯了什么错误? 他们只是给出了子集长度而不是实际子集。所以我基于所有子集长度的总和,我正在形成一个新数组

count = 0

def printCombination(arr, n, r):
    global count
    data = [0]*r
    combinationUtil(arr, data, 0,
                    n - 1, 0, r)


def combinationUtil(arr, data, start,
                    end, index, r):
    global count

    if (index == r):

        for j in range(r):
            print(data[j], end=" ")
        print()
        count += 1
        return
    i = start
    while(i <= end and end - i + 1 >= r - index):
        data[index] = arr[i]
        combinationUtil(arr, data, i + 1,
                        end, index + 1, r)
        i += 1

in_val = [1,2,1,1] 
arr = list(range(1,sum(in_val)+1)) r = 3 
n = len(arr) 
printCombination(arr, n, r) 
print(count)

我们可以用一些公式用最少的时间解决这个问题,而不是模拟每个子集并遍历。请对此有所了解或给我建议以进一步进行。

【问题讨论】:

  • 给定条件“您不能从一组中选择多个元素”为什么 {1,2,3} 有效?这不是从集合 {2,3} 中选择两个值吗? {1,3,4} 和 {1,4,3} 不是同一个集合吗?
  • @DarrylG 错误已更正
  • 不应允许同组
  • @johnwilson——为计数创建了一个函数(因为你提到只需要方法的数量)。如果您需要实际的套装,请告诉我。

标签: python algorithm data-structures


【解决方案1】:

假设所有输入集都是不相交的,动态规划方法允许我们在O(n) 时间内计算此类组合的数量,其中n 是集的数量(假设输入集的基数由一个常数限定; 否则,时间复杂度为O(n, max_size),其中max_size 是具有最大大小的输入集的基数。

import random # testing
from functools import lru_cache # memoization

xs = [{1},{2,3},{4},{5}]
k = 3
sizes = [len(x) for x in xs]
# [1, 2, 1, 1]

# dynamic programming approach
def count_combinations(sizes, k=3):
  @lru_cache(None)
  def f(n, k):
    if (n < k) or (k < 0):
      # no combination possible
      return 0
    elif n == k:
      # return product sizes[:n]
      res = 1
      for x in sizes[:n]:
        res *= x
      return res
    else:
      # recursive memoized call
      # f(n-1, k-1) ways to select k-1 elts from n-1 sets
      # times size of n-1'st set (counting from 0)
      # plus f(n-1, k) ways to select k elts from n-1 sets
      return sizes[n-1] * f(n-1, k-1) + f(n-1, k)
  return f(len(sizes), k)

# assert count_combs(sizes, k=k) == count_combinations(sizes, k)

# larger benchmark
n = 25
k = n // 2
xs = [{random.randint(0, n) for i in  range(n)} for _ in range(n)]
sizes = [len(x) for x in xs]

%time count_combs(sizes, k)          # O(n choose k), 8.6 s
%timeit count_combinations(sizes, k) # O(n), 112 µs

这避免了明确考虑大小 k 的所有可能组合,将复杂性从 O(n choose k) 降低到 O(n)

【讨论】:

  • 我的回答速度令人印象深刻。
【解决方案2】:

确定可以选择 K 尺寸集的方法数。

from itertools import combinations
from functools import reduce

def count_combs(arr, k):
  if k > len(arr):
    return 0  # Not possible
  elif k == len(arr):
    return reduce(lambda a, b: a*b, arr) # multiply values in arr
  else:
    """sum of answer to each sub-set of arr of size k
       subsets of arr of size k are combinations(arr, k)"""
    return sum(count_combs(x, k) for x in combinations(arr, k))

测试

arr = [1, 2, 1, 1]
print(count_combs(arr, 3))
# Outputs 7

arr = [1, 1, 1, 1]
print(count_combs(arr, 3))
# Outputs 4

arr = [1, 1, 1, 2]
print(count_combs(arr, 2))
# Output 9

说明

三种情况

  1. k > len(arr): 不可能,所以答案是 0
  2. k == len(arr):它是我们可以从每个数组索引中一次获取一个元素的方法数,它是数组 arr 值的乘积。
  3. k

【讨论】:

    猜你喜欢
    • 2020-03-12
    • 1970-01-01
    • 1970-01-01
    • 2012-08-20
    • 2022-01-19
    • 2011-07-24
    • 1970-01-01
    • 2013-06-20
    • 2021-10-20
    相关资源
    最近更新 更多