Finding permutations for balanced distribution of values in lists - algorithm

Sorry for the bad title, but I don't know how to call this.
I have K lists, N elements in each, for example:
[8, 5, 6]
[4, 3, 2]
[6, 5, 0]
and I want to find such a permutation of the lists' elements, so that the sum of elements in first column, second column etc are as close to each other as possible (so the distribution is "fair").
In my example that would be (probably):
[8, 5, 6]
[4, 2, 3] -- the lists contain the same values
[0, 6, 5] just in different order
sums: 12, 13, 14
Is there some more elegant way than finding all the permutations for each list, and brute-force finding the "ideal" combination of them?
I'm not asking for code, just give me a hint how to do it, if you know.
Thanks!
ps. the lists can be quite large, and more of them - think ~20x~20 max.

If you can accept an approximation, I would do it iteratively :
Sort matrix lines by descending weight (sum of line elements).
Edit : Sorting first by max element in line could be better.
Each time you are going to add a new line to your result matrix, put smaller elements into higher columns.
Order lines of your result matrix back to their initial state (if you have to).
It works with your example, but will obviously not be always perfect.
Here is an example (javascript)

Related

Return an index of the most common element in a list of integers with equal probability using O(1) space

I came across this coding problem and am having a hard time coming up with a solution.
Given an array of integers, find the most common element in a list of integers
and return any of its indexes randomly with equal probability. The solution must run in O(N) time and use O(1) space.
Example:
List contains: [-1, 4, 9, 7, 7, 2, 7, 3, 0, 9, 6, 5, 7, 8, 9]
7 is most common element so output should be one of: 3, 4, 6, 12
Now this problem would be fairly trivial if not for the constant space constraint. I know reservoir sampling can be used to solve the problem with these constraints if we know the the most common element ahead of time. But if we don't know the most common element, how could this problem be solved?

How to find the largest number in an array made by a ascendingly sorted array and a descendingly sorted array

for an array like [1, 2, 4, 6, 8, 7, 5], how do we efficiently find the largest number in it?
We know that the first part of the array is 1, 2, 4, 6, which is ascendingly sorted and the second part is 8, 7, 5 which is a descendingly sorted array.
The simply solution would be iterate through the array, but given the array is made of two sorted array, I would image the search can be done by some sort of binary search variation to achieve o(logn) runtime complexity. However I cannot seem to come up with the solution.
What you are asking for is equivalent to finding the "peak" of an array. Here is logarithmic time solution to the problem

Genetic algorithm, cross over without duplicate data

I'm creating a genetic algorithm and I just encounter a problem, let's take an example. I have a list of numbers : [2, 3, 6, 8, 9, 1, 4] which represent my datas.
The best solution to my problem depends on the order of the numbers in the list. So I have two solution : S1 [2, 3, 9, 8, 1, 6, 4] and S2 [1, 6, 4, 3, 9, 2, 8]
If I do a basic cross-over with S1 and S2 I may obtain a solution like this : child [2, 3, 9, 8, 9, 2, 8] and we can see that the solution is bad because I duplicate datas.
The question is how may I realized an evolution (so cross-over) without duplicate thoses datas ?
thanks.
You will need a crossover operator like Ordered Crossover (OX1) that can perform crossover without duplicate thoses datas:
OX1:
A randomly selected portion of one parent is mapped to a portion
of the other parent. From the replaced portion on, the rest is filled
up by the remaining genes, where already present genes are omitted and
the order is preserved.
You should take care with mutation too, because it can change the genes order, in this case you can use a mutation operator like Reverse Sequence Mutation (RSM).
In the reverse sequence mutation operator, we take a sequence S
limited by two positions i and j randomly chosen, such that i<j.
The gene order in this sequence will be reversed by the same way as
what has been covered in the previous operation.
You have Permutation Encoding, look at this explanation: http://www.obitko.com/tutorials/genetic-algorithms/crossover-mutation.php
In general you take the elements of the first parent in order in which they are met in the first parent and you take the rest of the elements in the order in which they are met in the second parent.

How to distribute a vector of n elements across p processors

Suppose I have a vector of n elements, and I want to distribute it on p processes, where n isn't necessary a multiple of p. Each process has a rank from 0 to p-1. How to determine how many elements will be on each process, to have data distributed the more evenly possible?
For example, if n=14 and p=4, I want a distribution like [3, 3, 4, 4] or [3, 4, 3, 4], but not [3, 3, 3, 5] nor [4, 4, 4, 2].
I want a function f(n, p, r) that returns me the number of elements for process with rank r.
Does
(n + r) / p
work for you?
This seems to be a special case of the Bin Packing problem. There are some very good approximation algorithms, but in theory it is NP-hard.
If you can't be bothered to read the wiki page, I'll cut it down into a few lines. If you want to look deeper for possibly better solutions, or for an analysis on how well the approximation schemes work, by all means.
Step 1: sort the elements by priority.
Step 2: grab the element with highest priority, and shove it on the least burdened process.
Step 3: If you have more elements, go to Step 1. Else return.

Find the middle element in merged arrays in O(logn)

We have two sorted arrays of the same size n. Let's call the array a and b.
How to find the middle element in an sorted array merged by a and b?
Example:
n = 4
a = [1, 2, 3, 4]
b = [3, 4, 5, 6]
merged = [1, 2, 3, 3, 4, 4, 5, 6]
mid_element = merged[(0 + merged.length - 1) / 2] = merged[3] = 3
More complicated cases:
Case 1:
a = [1, 2, 3, 4]
b = [3, 4, 5, 6]
Case 2:
a = [1, 2, 3, 4, 8]
b = [3, 4, 5, 6, 7]
Case 3:
a = [1, 2, 3, 4, 8]
b = [0, 4, 5, 6, 7]
Case 4:
a = [1, 3, 5, 7]
b = [2, 4, 6, 8]
Time required: O(log n). Any ideas?
Look at the middle of both the arrays. Let's say one value is smaller and the other is bigger.
Discard the lower half of the array with the smaller value. Discard the upper half of the array with the higher value. Now we are left with half of what we started with.
Rinse and repeat until only one element is left in each array. Return the smaller of those two.
If the two middle values are the same, then pick arbitrarily.
Credits: Bill Li's blog
Quite interesting task. I'm not sure about O(logn), but solution O((logn)^2) is obvious for me.
If you know position of some element in first array then you can find how many elements are smaller in both arrays then this value (you know already how many smaller elements are in first array and you can find count of smaller elements in second array using binary search - so just sum up this two numbers). So if you know that number of smaller elements in both arrays is less than N, you should look in to the upper half in first array, otherwise you should move to the lower half. So you will get general binary search with internal binary search. Overall complexity will be O((logn)^2)
Note: if you will not find median in first array then start initial search in the second array. This will not have impact on complexity
So, having
n = 4 and a = [1, 2, 3, 4] and b = [3, 4, 5, 6]
You know the k-th position in result array in advance based on n, which is equal to n.
The result n-th element could be in first array or second.
Let's first assume that element is in first array then
do binary search taking middle element from [l,r], at the beginning l = 0, r = 3;
So taking middle element you know how many elements in the same array smaller, which is middle - 1.
Knowing that middle-1 element is less and knowing you need n-th element you may have [n - (middle-1)]th element from second array to be smaller, greater. If that's greater and previos element is smaller that it's what you need, if it's greater and previous is also greater we need to L = middle, if it's smaller r = middle.
Than do the same for the second array in case you did not find solution for first.
In total log(n) + log(n)

Resources