Given an array A
of N
nonnegative numbers, I\'m interested in finding the number of ways you can pick 5 numbers (from distinct positions in the array)
Maybe it's better to create an array with only distinct values first and count the occurence of them in the originally array. Because only the number of solutions is wanted and not the solutions itself, that could be faster if using combination calculations.
1) Sort array A
O(N log N)
2) Create a new array B
where all values are distinct.
Also save the count of the occurence of the value in the original array A
for every element in B
. O(N)
3) Create a new array C
with sums of two elements of B
.
Including sums of the same element if the count > 1.
Also save the both indexes of the elements from B
. O(|B|2)
4) Sort array C
by the sums O(|B|2 (log |B|2))
5) For every element in B
find two valid elements from C
so that the three values sum up to S
and the indexes are in the same order. In pseudo code:
num=0
for (i=0; i 1 && i = c[j].index[m].left < c[j].index[m].right < c[j].index[k].left < c[j].index[k].right)
num+= binomialcoefficient(b[i].count, 2) * b[c[j].index[m].right].count * b[c[j].index[k].left].count * b[c[j].index[k].right].count
else if (b[c[j].index[m].left].count > 1 && i < c[j].index[m].left = c[j].index[m].right < c[j].index[k].left < c[j].index[k].right)
num+= b[i].count * binomialcoefficient(b[c[j].index[m].left].count, 2) * b[c[j].index[k].left].count * b[c[j].index[k].right].count
[..]
else if (b[i].count > 2 && i = c[j].index[m].left = c[j].index[m].right < c[j].index[k].left < c[j].index[k].right)
num+= binomialcoefficient(b[i].count, 3) * b[c[j].index[k].left].count * b[c[j].index[k].right].count
[..]
else if (b[i].count > 1 && b[c[j].index[m].right].count > 1 && i = c[j].index[m].left < c[j].index[m].right = c[j].index[k].left < c[j].index[k].right)
num+= binomialcoefficient(b[i].count, 2) * binomialcoefficient(b[c[j].index[m].right].count, 2) * b[c[j].index[k].right].count
[..]
else if (b[i].count > 4 && i = c[j].index[m].left = c[j].index[m].right = c[j].index[k].left = c[j].index[k].right)
num+= binomialcoefficient(b[i].count, 5)
if (c[j].sum + c[k].sum >= S - b[i].value)
k--
if (c[j].sum + c[k].sum <= S - b[i].value)
j++
I'm not really sure what time complexity this has. The outer for loop is bound by O(|B|), the while loop by O(|B|2), the inner for loops by O(|B|), because B
has only distinct values.
So obvisouly it's in O(|B|5). But its O(N) if all elements in A
have the same value and if all values are distinct and sufficiently random its maybe possible to bound the number of indexes per sum in C
by a constant, which would lead to O(N3).
The worst case could be somewhere with half the values equal and the other half random or with all numbers distinct but a lot of duplicate sums. But that would also lead to a much shorter while loop. I have a feeling that the while and the two inner for loops are bound by O(N2), so O(N3) in total for all cases, but i can't proof it.
Also an interesting question here is what is the maximum number of possibilities to pick up 5 numbers which sum to S for an array of N disctinct numbers. If it is in O(N5) the worst case of that algorithm is also O(N5).
Maybe try it out ;).