Algorithm for combination index in array - algorithm

I know how to compute the binomial coefficient given n and k (and I use a library for that).
Now imagine you store all of those combinations inside an array. Each combination has an index. I don't actually need to store them in an array, but I need to know, if I were to store them, what the array index would be for each combination.
E.g. given an element of the C(n,k) set of possible combinations, I need a function that gives me its index i inside the array, withtout actually creating the whole array. The programming language does not matter, though I need to implement the function in java, but any (pseudo-)language algorithm will do, I will then translate it to java.
For example, in the case of n=5 and k=2, I empirically define this function f(n, k, [a,b]) => N as:
f(5, 2, [1,2]) = 0
f(5, 2, [1,3]) = 1
f(5, 2, [1,4]) = 2
f(5, 2, [1,5]) = 3
f(5, 2, [2,3]) = 4
f(5, 2, [2,4]) = 5
f(5, 2, [2,5]) = 6
f(5, 2, [3,4]) = 7
f(5, 2, [3,5]) = 8
f(5, 2, [4,5]) = 9
meaning that the (3,5) combination would occupy index 8 in the array. Another example with n=5 and k=3 is f(n, k, [a,b,c]) => N, empirically defined as
f(5, 3, [1,2,3]) = 0
f(5, 3, [1,2,4]) = 1
f(5, 3, [1,2,5]) = 2
f(5, 3, [1,3,4]) = 3
f(5, 3, [1,3,5]) = 4
f(5, 3, [1,4,5]) = 5
f(5, 3, [2,3,4]) = 6
f(5, 3, [2,3,5]) = 7
f(5, 3, [2,4,5]) = 8
f(5, 3, [3,4,5]) = 9
EDIT for clarification after comments:
In the example above [1,2,3], [2,4,5] and so on, are one of the elements of the C(n,k) set, e.g. one of the possible combinations of k numbers out of n possible numbers. The function needs them in order to compute their index in the array.
However I need to write this function for generic values of n and k and without creating the array. Maybe such a function already exists in some combinatorial calculus library, but I don't even know how it would be called.

You should have a look at the combinatorial number system, the section "Place of a combination in the ordering" in particular.
There is even an example, which might help you: National Lottery example in Excel. (I'm sorry, but I can't type any math in here.)
In your case this would be
f(5, 3, [2,3,4]) = binom(5,3) - 1 - binom(5-2,3) - binom(5-3,2) - binom(5-4,1) =
= 10 - 1 - 1 - 1 - 1 = 6
or if you accept a reversed order, you may omit the binom(5,3) - 1 part and calculate
f'(5, 3, [2,3,4]) = binom(5-2,3) + binom(5-3,2) + binom(5-4,1) - 1 =
= 1 + 1 + 1 - 1 = 2
(This should save you some time, as binom(5, 3) is not really necessary here.)
In Java the method could be
int f(int n, int k, int[] vars) {
int res = binom(n, k) - 1;
for(int i = 0; i < k; i++) {
res -= binom(n - vars[i], k - i);
}
return res;
}
or
int fPrime(int n, int k, int[] vars) {
int res = -1;
for(int i = 0; i < k; i++) {
res += binom(n - vars[i], k - i);
}
return res;
}
assuming a method int binom(int n, int k) and binom(n, k) = 0 for n < k.

Related

Find greater number form self in left side and smaller number form self in right side

Consider an array a of n integers, indexed from 1 to n.
For every index i such that 1<i<n, define:
count_left(i) = number of indices j such that 1 <= j < i and a[j] > a[i];
count_right(i) = number of indices j such that i < j <= n and a[j] < a[i];
diff(i) = abs(count_left(i) - count_right(i)).
The problem is: given array a, find the maximum possible value of diff(i) for 1 < i < n.
I got solution by brute force. Can anyone give better solution?
Constraint: 3 < n <= 10^5
Example
Input Array: [3, 6, 9, 5, 4, 8, 2]
Output: 4
Explanation:
diff(2) = abs(0 - 3) = 3
diff(3) = abs(0 - 4) = 4
diff(4) = abs(2 - 2) = 0
diff(5) = abs(3 - 1) = 2
diff(6) = abs(1 - 1) = 0
maximum is 4.
O(nlogn) approach:
Walk through array left to right and add every element to augmented binary search tree (RB, AVL etc) containing fields of subtree size, initial index and temporary rank field. So immediately after adding we know rank of element in the current tree state.
lb = index - temprank
is number of left bigger elements - remember it in temprank field.
After filling the tree with all items traverse tree again, retrieving final element rank.
rs = finalrank - temprank
is number of right smaller elements. Now just get abs of difference of lb and rs
diff = abs(lb - rs) = abs(index - temprank - finalrank + temprank ) =
abs(index - finalrank)
But ... we can see that we don't need temprank at all.
Moreover - we don't need binary tree!
Just perform sorting of pairs (element; initial index) by element key and get max absolute difference of new_index - old_index (except for old indices 1 and n)
a 3, 6, 9, 5, 4, 8, 2
old 2 3 4 5 6
new 5 7 4 3 6
dif 3 4 0 2 0
Python code for concept checking
a = [3, 6, 9, 5, 4, 8, 2]
b = sorted([[e,i] for i,e in enumerate(a)])
print(b)
print(max([abs(n-o[1]) if 0<o[1]<len(a)-1 else 0 for n,o in enumerate(b)]))

Finding the maximum possible sum/product combination of integers

Given an input of a list of N integers always starting with 1, for example: 1, 4, 2, 3, 5. And some target integer T.
Processing the list in order, the algorithm decides whether to add or multiply the number by the current score to achieve the maximum possible output < T.
For example: [input] 1, 4, 2, 3, 5 T=40
1 + 4 = 5
5 * 2 = 10
10 * 3 = 30
30 + 5 = 35 which is < 40, so valid.
But
1 * 4 = 4
4 * 2 = 8
8 * 3 = 24
24 * 5 = 120 which is > 40, so invalid.
I'm having trouble conceptualizing this in an algorithm -- I'm just looking for advice on how to think about it or at most pseudo-code. How would I go about coding this?
My first instinct was to think about the +/* as 1/0, and then test permutations like 0000 (where length == N-1, I think), then 0001, then 0011, then 0111, then 1111, then 1000, etc. etc.
But I don't know how to put that into pseudo-code given a general N integers. Any help would be appreciated.
You can use recursive to implement the permutations. Python code below:
MINIMUM = -2147483648
def solve(input, T, index, temp):
# if negative value exists in input, remove below two lines
if temp >= T:
return MINIMUM
if index == len(input):
return temp
ans0 = solve(input, T, index + 1, temp + input[index])
ans1 = solve(input, T, index + 1, temp * input[index])
return max(ans0, ans1)
print(solve([1, 4, 2, 3, 5], 40, 1, 1))
But this method requires O(2^n) time complexity.

Algorithm to finding if the numbers in the list, when added or subtracted, are equal to a mod b

I was doing some interview problems when I ran into an interesting one that I could not think of a solution for. The problems states:
Design a function that takes in an array of integers. The last two numbers
in this array are 'a' and 'b'. The function should find if all of the
numbers in the array, when summed/subtracted in some fashion, are equal to
a mod b, except the last two numbers a and b.
So, for example, let us say we have an array:
array = [5, 4, 3, 3, 1, 3, 5].
I need to find out if there exists any possible "placement" of +/- in this array so that the numbers can equal 3 mod 5. The function should print True for this array because 5+4-3+3-1 = 8 = 3 mod 5.
The "obvious" and easy solution would be to try and add/subtract everything in all possible ways, but that is an egregiously time complex solution, maybe
O(2n).
Is there any way better to do this?
Edit: The question requires the function to use all numbers in the array, not any. Except, of course, the last two.
If there are n numbers, then there is a simple algorithm that runs in O (b * n): For k = 2 to n, calculate the set of integers x such that the sum or difference of the first k numbers is equal to x modulo b.
For k = 2, the set contains (a_0 + a_1) modulo b and (a_0 - a_1) modulo b. For k = 3, 4, ..., n you take the numbers in the previous set, then either add or subtract the next number in the array. And finally check if a is element of the last set.
O(b * n). Let's take your example, [5, 4, 3, 3, 1]. Let m[i][j] represent whether a solution exists for j mod 5 up to index i:
i = 0:
5 = 0 mod 5
m[0][0] = True
i = 1:
0 + 4 = 4 mod 5
m[1][4] = True
but we could also subtract
0 - 4 = 1 mod 5
m[1][1] = True
i = 2:
Examine the previous possibilities:
m[1][4] and m[1][1]
4 + 3 = 7 = 2 mod 5
4 - 3 = 1 = 1 mod 5
1 + 3 = 4 = 4 mod 5
1 - 3 = -2 = 3 mod 5
m[2][1] = True
m[2][2] = True
m[2][3] = True
m[2][4] = True
i = 3:
1 + 3 = 4 mod 5
1 - 3 = 3 mod 5
2 + 3 = 0 mod 5
2 - 3 = 4 mod 5
3 + 3 = 1 mod 5
3 - 3 = 0 mod 5
4 + 3 = 2 mod 5
4 - 3 = 1 mod 5
m[3][0] = True
m[3][1] = True
m[3][2] = True
m[3][3] = True
m[3][4] = True
We could actually stop there, but let's follow a different solution than the one in your example backwards:
i = 4:
m[3][2] True means we had a solution for 2 at i=3
=> 2 + 1 means m[4][3] = True
+ 1
+ 3
+ 3
- 4
(0 - 4 + 3 + 3 + 1) = 3 mod 5
I coded a solution based on the mathematical explanation provided here. I didn't comment the solution, so if you want an explanation, I recommend you read the answer!
def kmodn(l):
k, n = l[-2], l[-1]
A = [0] * n
count = -1
domath(count, A, l[:-2], k, n)
def domath(count, A, l, k, n):
if count == len(l):
boolean = A[k] == 1
print boolean
elif count == -1:
A[0] = 1; # because the empty set is possible
count += 1
domath(count, A, l, k, n)
else:
indices = [i for i, x in enumerate(A) if x == 1]
b = [0] * n
for i in indices:
idx1 = (l[count] + i) % n
idx2 = (i - l[count]) % n
b[idx1], b[idx2] = 1, 1
count += 1
A = b
domath(count, A, l, k, n)

Find algorithm to split sequence in 2 to minimize difference in sum [duplicate]

This question already has answers here:
Is partitioning an array into halves with equal sums P or NP?
(5 answers)
Closed 9 years ago.
Here's the problem: given a sequence of numbers, split these numbers into 2 sequences, so that the difference between the two sequences is the minimum. For example, given the sequence: [5, 4, 3, 3, 3] the solution is:
[5, 4] -> sum is 9
[3, 3, 3] -> sum is 9
The difference is 0
In other terms, can you find an algorithm (C language preferred) that given an input vector (variable size) of integers, can output two vector where the difference between the two sum is minimum?
Brutal force algorithm should be avoided.
To be sure to get the right solution, should be nice to compare in a benchmark the results between your algorithm and a brutal force algorithm.
It sounds like a sub-arrays problem (which is my interpretation of "sequences").
Meaning the only possibilities for 5, 4, 3, 3, 3 are:
| 5, 4, 3, 3, 3 => 0 - 18 => 18
5 | 4, 3, 3, 3 => 5 - 13 => 8
5, 4 | 3, 3, 3 => 9 - 9 => 0
5, 4, 3 | 3, 3 => 12 - 6 => 6
5, 4, 3, 3 | 3 => 15 - 3 => 12
5, 4, 3, 3, 3 | => 18 - 0 => 18 (same as first)
It is as simple as just comparing the sums on either side of every index.
Code: (untested)
int total = 0;
for (int i = 0; i < n; i++)
total += arr[i];
int best = INT_MAX, bestPos = -1, current = 0;
for (int i = 0; i < n; i++)
{
current += arr[i];
int diff = abs(current - total);
if (diff < best)
{
best = diff;
bestPos = i;
}
// else break; - optimisation, may not work
}
printf("The best position is at %d\n", bestPos);
The above is O(n), logically, you can't do much better than that.
You can slightly optimize the above by doing a binary-search-like process on the sequence to get down to n + log n rather than 2n, but both are O(n). Basic pseudo-code:
sum[0] = arr[0]
// sum[i] represents sum from indices 0 to i
for (i = 1:n)
sum[i] = sum[i-1] + arr[i]
total = sum[n]
start = 0
end = n
best = MAX
repeat:
if (start == end) stop
mid = (start + end) / 2
sumFromMidToN = sum[n] - sum[mid]
best = max(best, abs(sumFromMidToN - sum[mid]))
if (sum[mid] > sumFromMidToN)
end = mid
else if (sum[mid] < sumFromMidToN)
start = mid
else
stop
If it's actually subsets, then, as already mentioned, it appears to be the optimization version of the Partition problem, which is a lot more difficult.

Link list algorithm to find pairs adding up to 10

Can you suggest an algorithm that find all pairs of nodes in a link list that add up to 10.
I came up with the following.
Algorithm: Compare each node, starting with the second node, with each node starting from the head node till the previous node (previous to the current node being compared) and report all such pairs.
I think this algorithm should work however its certainly not the most efficient one having a complexity of O(n2).
Can anyone hint at a solution which is more efficient (perhaps takes linear time). Additional or temporary nodes can be used by such a solution.
If their range is limited (say between -100 and 100), it's easy.
Create an array quant[-100..100] then just cycle through your linked list, executing:
quant[value] = quant[value] + 1
Then the following loop will do the trick.
for i = -100 to 100:
j = 10 - i
for k = 1 to quant[i] * quant[j]
output i, " ", j
Even if their range isn't limited, you can have a more efficient method than what you proposed, by sorting the values first and then just keeping counts rather than individual values (same as the above solution).
This is achieved by running two pointers, one at the start of the list and one at the end. When the numbers at those pointers add up to 10, output them and move the end pointer down and the start pointer up.
When they're greater than 10, move the end pointer down. When they're less, move the start pointer up.
This relies on the sorted nature. Less than 10 means you need to make the sum higher (move start pointer up). Greater than 10 means you need to make the sum less (end pointer down). Since they're are no duplicates in the list (because of the counts), being equal to 10 means you move both pointers.
Stop when the pointers pass each other.
There's one more tricky bit and that's when the pointers are equal and the value sums to 10 (this can only happen when the value is 5, obviously).
You don't output the number of pairs based on the product, rather it's based on the product of the value minus 1. That's because a value 5 with count of 1 doesn't actually sum to 10 (since there's only one 5).
So, for the list:
2 3 1 3 5 7 10 -1 11
you get:
Index a b c d e f g h
Value -1 1 2 3 5 7 10 11
Count 1 1 1 2 1 1 1 1
You start pointer p1 at a and p2 at h. Since -1 + 11 = 10, you output those two numbers (as above, you do it N times where N is the product of the counts). Thats one copy of (-1,11). Then you move p1 to b and p2 to g.
1 + 10 > 10 so leave p1 at b, move p2 down to f.
1 + 7 < 10 so move p1 to c, leave p2 at f.
2 + 7 < 10 so move p1 to d, leave p2 at f.
3 + 7 = 10, output two copies of (3,7) since the count of d is 2, move p1 to e, p2 to e.
5 + 5 = 10 but p1 = p2 so the product is 0 times 0 or 0. Output nothing, move p1 to f, p2 to d.
Loop ends since p1 > p2.
Hence the overall output was:
(-1,11)
( 3, 7)
( 3, 7)
which is correct.
Here's some test code. You'll notice that I've forced 7 (the midpoint) to a specific value for testing. Obviously, you wouldn't do this.
#include <stdio.h>
#define SZSRC 30
#define SZSORTED 20
#define SUM 14
int main (void) {
int i, s, e, prod;
int srcData[SZSRC];
int sortedVal[SZSORTED];
int sortedCnt[SZSORTED];
// Make some random data.
srand (time (0));
for (i = 0; i < SZSRC; i++) {
srcData[i] = rand() % SZSORTED;
printf ("srcData[%2d] = %5d\n", i, srcData[i]);
}
// Convert to value/size array.
for (i = 0; i < SZSORTED; i++) {
sortedVal[i] = i;
sortedCnt[i] = 0;
}
for (i = 0; i < SZSRC; i++)
sortedCnt[srcData[i]]++;
// Force 7+7 to specific count for testing.
sortedCnt[7] = 2;
for (i = 0; i < SZSORTED; i++)
if (sortedCnt[i] != 0)
printf ("Sorted [%3d], count = %3d\n", i, sortedCnt[i]);
// Start and end pointers.
s = 0;
e = SZSORTED - 1;
// Loop until they overlap.
while (s <= e) {
// Equal to desired value?
if (sortedVal[s] + sortedVal[e] == SUM) {
// Get product (note special case at midpoint).
prod = (s == e)
? (sortedCnt[s] - 1) * (sortedCnt[e] - 1)
: sortedCnt[s] * sortedCnt[e];
// Output the right count.
for (i = 0; i < prod; i++)
printf ("(%3d,%3d)\n", sortedVal[s], sortedVal[e]);
// Move both pointers and continue.
s++;
e--;
continue;
}
// Less than desired, move start pointer.
if (sortedVal[s] + sortedVal[e] < SUM) {
s++;
continue;
}
// Greater than desired, move end pointer.
e--;
}
return 0;
}
You'll see that the code above is all O(n) since I'm not sorting in this version, just intelligently using the values as indexes.
If the minimum is below zero (or very high to the point where it would waste too much memory), you can just use a minVal to adjust the indexes (another O(n) scan to find the minimum value and then just use i-minVal instead of i for array indexes).
And, even if the range from low to high is too expensive on memory, you can use a sparse array. You'll have to sort it, O(n log n), and search it for updating counts, also O(n log n), but that's still better than the original O(n2). The reason the binary search is O(n log n) is because a single search would be O(log n) but you have to do it for each value.
And here's the output from a test run, which shows you the various stages of calculation.
srcData[ 0] = 13
srcData[ 1] = 16
srcData[ 2] = 9
srcData[ 3] = 14
srcData[ 4] = 0
srcData[ 5] = 8
srcData[ 6] = 9
srcData[ 7] = 8
srcData[ 8] = 5
srcData[ 9] = 9
srcData[10] = 12
srcData[11] = 18
srcData[12] = 3
srcData[13] = 14
srcData[14] = 7
srcData[15] = 16
srcData[16] = 12
srcData[17] = 8
srcData[18] = 17
srcData[19] = 11
srcData[20] = 13
srcData[21] = 3
srcData[22] = 16
srcData[23] = 9
srcData[24] = 10
srcData[25] = 3
srcData[26] = 16
srcData[27] = 9
srcData[28] = 13
srcData[29] = 5
Sorted [ 0], count = 1
Sorted [ 3], count = 3
Sorted [ 5], count = 2
Sorted [ 7], count = 2
Sorted [ 8], count = 3
Sorted [ 9], count = 5
Sorted [ 10], count = 1
Sorted [ 11], count = 1
Sorted [ 12], count = 2
Sorted [ 13], count = 3
Sorted [ 14], count = 2
Sorted [ 16], count = 4
Sorted [ 17], count = 1
Sorted [ 18], count = 1
( 0, 14)
( 0, 14)
( 3, 11)
( 3, 11)
( 3, 11)
( 5, 9)
( 5, 9)
( 5, 9)
( 5, 9)
( 5, 9)
( 5, 9)
( 5, 9)
( 5, 9)
( 5, 9)
( 5, 9)
( 7, 7)
Create a hash set (HashSet in Java) (could use a sparse array if your numbers are well-bounded, i.e. you know they fall into +/- 100)
For each node, first check if 10-n is in the set. If so, you have found a pair. Either way, then add n to the set and continue.
So for example you have
1 - 6 - 3 - 4 - 9
1 - is 9 in the set? Nope
6 - 4? No.
3 - 7? No.
4 - 6? Yup! Print (6,4)
9 - 1? Yup! Print (9,1)
This is a mini subset sum problem, which is NP complete.
If you were to first sort the set, it would eliminate the pairs of numbers that needed to be evaluated.

Resources