找到具有最大和的n个数组合的算法

时间:2015-04-08 17:48:38

标签: algorithm puzzle

问题很简单 - 假设我有一系列以下数字 - 4,1,4,5,7,4,3,1,5 我必须找到k个元素的集合,每个元素可以从具有最大总和的上述数字创建。如果两组具有至少一个不同的元素,则认为它们是不同的。 例如 如果k = 2,则可以有两组 - {7,5}和{7,5}。注意:5在上面的数组中出现两次。

我想我可以从以下事情开始: 1.排序数组 2.创建两个数组。一个用于不同的数字,另一个用于数字的出现。

但我现在被困住了。有什么建议?

4 个答案:

答案 0 :(得分:3)

算法如下:

1)按降序排列元素。

2)看看这个数组。它可能看起来像这样:

   a ... a b ... b c ... c d ...
   |  <-    k   ->    | 

现在显然所有元素ab都将在具有最大总和的集合中。您不能用较小的元素替换它们中的任何一个,因为这样的总和不会是最大的。所以你别无选择,你必须为任何集合选择所有ab

另一方面,只有元素c的某些将存在于这些集合中。所以答案就是可能的数量,在你选择所有更大的元素之后,选择c来填充集合中剩余的位置。这是二项式系数:

count of c's 选择 (k - (count of elements larger than c))

例如对于数组(已在此处排序)

[9, 8, 7, 7, 5, 5, 5, 5, 4, 4, 2, 2, 1, 1, 1]

k = 6必须为每个具有最大总和(即41)的集合选择9,8和7。然后你可以从四个 5中选择任何两个。结果将是4 choose 2 = 6

使用相同的数组和k = 4,结果为x choose 0 = 1(该唯一集为{9, 8, 7, 7}),k = 7结果为4 choose 3 = 4 ,以及k = 92 choose 1 = 2(为具有最大总和的集合选择任意4)。

答案 1 :(得分:2)

编辑:我编辑了答案,因为我们发现OP需要统计多个集合。

首先,找到数组中最大的k个数字。这当然很简单,如果k非常小,您可以通过执行O(k)线性扫描在k中执行此操作。如果k不是那么小,您可以使用二进制堆或优先级队列,或者只是对数组进行排序,以便在使用排序时分别执行O(n * log(k))O(n * log(n))

假设您计算了k个最大数字。当然,具有最大总和的所有大小k的集合必须包含这些k最大数字而不包含其他数字。另一方面,任何不同的集合都不具有最大的总和。

count[i]为输入序列中出现的数字i

occ[i]为最大i个数字中k个出现次数。

我们可以用非常不同的方式计算这两个表,例如使用哈希表,或者如果输入数字很小,你可以使用由这些数字索引的数组。

B成为最大k个数字中不同数字的数组。 设mB的大小。

现在让我们来计算答案。我们将在m步骤中执行此操作。在i步之后,我们将计算由i中的第一个B数字组成的不同多重集的数量。开头的结果是1,因为只有一个空的多重集。在i - 步骤中,我们将当前结果乘以occ[B[i]]元素count[B[i]]元素的可能选择数,等于binomial(occ[i], count[i])

例如,让我们考虑您的实例,最后添加7个,k设置为3:

  

k = 3

     

A = [4,1,4,5,7,4,3,1,5,7]

A中最大的三个数字是7, 7, 5

一开始我们有:

count[7] = 2
count[5] = 2
occ[7] = 2
occ[5] = 1
result = 1
B = [7, 5]

我们从B中的第一个元素开始,它是7.它的count是2,它的occ也是2,所以我们这样做:

// binomial(2, 2) is 1
result = result * binomial(2, 2) 

B中的下一个元素是5,其count是2,其occ是1,所以我们这样做:

// binomial(2, 1) is 2
result = result * binomial(2, 1) 

最终结果是2,因为有两个不同的多重集[7, 7, 5]

答案 2 :(得分:1)

我会创建一个排序字典,列出输入中数字的出现频率。然后取两个最大的数字并乘以它们出现的次数。

在C ++中,它看起来像这样:

std::vector<int> inputs { 4, 1, 4, 5, 7, 3, 1, 5};
std::map<int, int> counts;

for (auto i : inputs) 
    ++counts[i];

auto last = counts.rbegin();

int largest_count = *last;
int second_count = *++last;

int set_count = largeest_count * second_count;

答案 3 :(得分:0)

您可以执行以下操作:

1)按降序排列元素;

2)定义变量answer = 1;

3)从数组的开头开始,对于您看到的每个新值,计算其出现次数(让我们调用此变量计数)。每次都做:回答=回答*算。伪代码应如下所示。

find_count(Array A, K)
{
   sort(A,'descending);
   int answer=1;
   int count=1;
   for (int i=1,j=1; i<K && j<A.length;j++)
   {
        if(A[i] != A[i-1])
        {
            answer = answer *count;
            i++;
            count=1;
        }
        else
            count++;
   }
      return answer;
}