问题很简单 - 假设我有一系列以下数字 - 4,1,4,5,7,4,3,1,5 我必须找到k个元素的集合,每个元素可以从具有最大总和的上述数字创建。如果两组具有至少一个不同的元素,则认为它们是不同的。 例如 如果k = 2,则可以有两组 - {7,5}和{7,5}。注意:5在上面的数组中出现两次。
我想我可以从以下事情开始: 1.排序数组 2.创建两个数组。一个用于不同的数字,另一个用于数字的出现。
但我现在被困住了。有什么建议?
答案 0 :(得分:3)
算法如下:
1)按降序排列元素。
2)看看这个数组。它可能看起来像这样:
a ... a b ... b c ... c d ...
| <- k -> |
现在显然所有元素a
和b
都将在具有最大总和的集合中。您不能用较小的元素替换它们中的任何一个,因为这样的总和不会是最大的。所以你别无选择,你必须为任何集合选择所有a
和b
。
另一方面,只有元素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 = 9
:2 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
个数字中不同数字的数组。
设m
为B
的大小。
现在让我们来计算答案。我们将在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;
}