Split an array into 4 portions - java

I have to create a method that divides the array of integers taken as input into an array that is made in this way:
The first portion is composed of the elements which, divided by 4, generate rest 0
The second portion is composed of the elements which, divided by 4, give rest 1
The third portion is composed of the elements which, divided by 4, give remainder 2
The fourth portion is composed of the elements, divided by 4, give rest 3
For example, the following array:
[0,2,4,5,6,8,7,9,10,12,14,15,17,20,1]
must become this here:
[0,4,8,12,20,5,9,17,1,2,6,10,14,7,15]
The result I get is:
[0,4,5,8,6,2,7,9,10,12,14,15,17,20,1]
Within subsequences no matter the order of items, just be in the subsequence correct.
I wrote this method but doen't work properly, some items are out of place.
public static void separate4Colors(int[] a) {
int i = 0;
int j = 0;
int k = 0;
int h = a.length - 1;
while(k <= h) {
if(a[k] % 4 == 0) {
swap(a, k, i);
k++;
i++;
j++;
}
else if(a[k] % 4 == 1) {
swap(a, k, i);
k++;
i++;
}
else if(a[k] % 4 == 2) {
k++;
}
else {
while(h > k && a[k] % 4 == 3)
h--;
swap(a, k, h);
h--;
}
}
}
private static void swap(int[] a, int x, int y) {
int temp = a[x];
a[x] = a[y];
a[y] = temp;
}
Can someone help me fix it?
A similar exercise that I've done and that work is to divide the array into 3 portions instead that 4:
public static void separate3Colors(int[] a) {
int j = 0;
int k = a.length - 1;
int i = 0;
while(j <= k) {
if(a[j] % 3 == 0) {
swap(a, j, i);
j++;
i++;
}
else if(a[j] % 3 == 1) {
j++;
}
else {
swap(a, j, k);
k--;
}
}
}

You can do it in a single line by sorting the array using a comparator that compares numbers modulo 4. Unfortunately, it requires an array of Integer objects.
Another approach would be writing the results into a different array. You can walk the array once to determine indexes at which the values with each remainder will start, and then walk the array again to make an ordered copy:
int[] index = new int[4];
for(int n : a) {
int r = n % 4;
if (r != 3) {
index[r+1]++;
}
}
index[2] += index[1];
index[3] += index[2];
// At this point each index[k] has the position where elements
// with remainder of k will start
int[] res = new int[a.length];
for(int n : a) {
res[index[n%4]++] = n;
}
This places the re-ordered array into the res variable.
Demo.

This exercice is obviously a variant of the famous Dutch National Flag Problem by the late E. Dijkstra https://en.wikipedia.org/wiki/Dutch_national_flag_problem
and the same resolution technique can be applied (with success, of course).
Consider that, at some point while running your algorithm, the arrays has five parts. One part contains numbers you know have with remainder 0, one part for remainders 1, etc. And one part for unclassified numbers. Each step of the algorithm consists of
looking at the first unclassified number
swapping some numbers at the borders so the number falls in the right part.
So the "unsorted" zone shrinks by one unit.
Sometimes a picture helps (go figure). I chose the have the unclassified elements between the 1's and the 2's.
000000000111111uuuuuuu22222333333333
?
If remainder of the number under test is 1, just leave it there. If it is zero, swap it with the first "1". etc.
At the beginning, of course, the situation is depicted as
uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
?

Related

How to implement a k-way merge sort?

I need to implement a function which does a k-way merge sort on an unsorted array or integers.
The function takes in two parameters, an integer K, which is the "way" of the sort and always a power of 2. The second parameter is the array of integers to be sorted, whose length is also a power of 2.
The function is to return an array containing the sorted elements. So far, I know how to implement a regular merge sort. How would I modify this code so that it implements a K-way merge sort? (Note: this function doesn't return the sorted array, I need help with that as well. It also doesn't take in K, since its a regular merge sort)
Below code:
public class MergeSort {
public static void main(String[] args) {
}
public static void mergeSort(int[] inputArray) {
int size = inputArray.length;
if (size < 2)
return;
int mid = size / 2;
int leftSize = mid;
int rightSize = size - mid;
int[] left = new int[leftSize];
int[] right = new int[rightSize];
for (int i = 0; i < mid; i++) {
left[i] = inputArray[i];
}
for (int i = mid; i < size; i++) {
right[i - mid] = inputArray[i];
}
mergeSort(left);
mergeSort(right);
merge(left, right, inputArray);
}
public static void merge(int[] left, int[] right, int[] arr) {
int leftSize = left.length;
int rightSize = right.length;
int i = 0, j = 0, k = 0;
while (i < leftSize && j < rightSize) {
if (left[i] <= right[j]) {
arr[k] = left[i];
i++;
k++;
} else {
arr[k] = right[j];
k++;
j++;
}
}
while (i < leftSize) {
arr[k] = left[i];
k++;
i++;
}
while (j < leftSize) {
arr[k] = right[j];
k++;
j++;
}
}
}
Regular merge sort is two-way sorting. You compare elements from the first and the second halves of array and copy smallest to output array.
For k-way sorting you divide input array into K parts. K indexes point to the first elements of every part. To effectively choose the smallest of them, use priority queue (based on binary heap) and pop the smallest element from the heap top at every step. When you pop element belonging to the m-th part, push the next element from the same part (if it still exists)
Let you have array length 16 and k = 4.
The first recursion level calls 4 mergesorts for arrays copied from indexes 0..3, 4..7, 8..11, 12..15.
The second recursion level gets length 4 array and calls 4 mergesorts for 1-element arrays.
The third recursion level gets length 1 array and immediately returns (such array is sorted).
Now at the second recursion level you merge 4 one-element arrays into one sorted array.
Now at the first recursion level you merge 4 four-element arrays into one sorted array length 16

Divide an Array in equal size, such that value of given function is minimum

I've came across the following problem statement.
You have a list of natural numbers of size N and you must distribute the values in two lists A and B of size N/2, so that the squared sum of A elements is the nearest possible to the multiplication of the B elements.
Example:
Consider the list 7 11 1 9 10 3 5 13 9 12.
The optimized distribution is:
List A: 5 9 9 12 13
List B: 1 3 7 10 11
which leads to the difference abs( (5+9+9+12+13)^2 - (1*3*7*10*11) ) = 6
Your program should therefore output 6, which is the minimum difference that can be achieved.
What I've tried:
I've tried Greedy approach in order to solve this problem. I took two variables sum and mul. Now I started taking elements from the given set one by one and tried adding it in both the variables and calculated current
square of sum and multiplication. Now finalize the element in one of the two sets, such that the combination gives minimum possible value.
But this approach is not working in the given example itselt. I can't figure out what approach could be used here.
I'm not asking for exact code for the solution. Any possible approach and the reason why it is working, would be fine.
EDIT:
Source: CodinGame, Community puzzle
Try out this:
import java.util.Arrays;
public class Test {
public static void main(String [] args){
int [] arr = {7, 11, 1, 9, 10, 3, 5, 13, 9, 12};
int [][] res = combinations(5, arr);
int N = Arrays.stream(arr).reduce(1, (a, b) -> a * b);
int min = Integer.MAX_VALUE;
int [] opt = new int [5];
for (int [] i : res){
int k = (int) Math.abs( Math.pow(Arrays.stream(i).sum(), 2) - N/(Arrays.stream(i).reduce(1, (a, b) -> a * b)));
if(k < min){
min = k;
opt = i;
}
}
Arrays.sort(opt);
System.out.println("minimum difference is "+ min + " with the subset containing this elements " + Arrays.toString(opt));
}
// returns all k-sized subsets of a n-sized set
public static int[][] combinations(int k, int[] set) {
int c = (int) binomial(set.length, k);
int[][] res = new int[c][Math.max(0, k)];
int[] ind = k < 0 ? null : new int[k];
for (int i = 0; i < k; ++i) {
ind[i] = i;
}
for (int i = 0; i < c; ++i) {
for (int j = 0; j < k; ++j) {
res[i][j] = set[ind[j]];
}
int x = ind.length - 1;
boolean loop;
do {
loop = false;
ind[x] = ind[x] + 1;
if (ind[x] > set.length - (k - x)) {
--x;
loop = x >= 0;
} else {
for (int x1 = x + 1; x1 < ind.length; ++x1) {
ind[x1] = ind[x1 - 1] + 1;
}
}
} while (loop);
}
return res;
}
// returns n choose k;
// there are n choose k combinations without repetition and without observance of the sequence
//
private static long binomial(int n, int k) {
if (k < 0 || k > n) return 0;
if (k > n - k) {
k = n - k;
}
long c = 1;
for (int i = 1; i < k+1; ++i) {
c = c * (n - (k - i));
c = c / i;
}
return c;
}
}
Code taken from this stackoverflow answer, also take a look at this wikipedia article about Combinations.
I am not sure if there is any exact solution in polynomial time. But you could try a simulated annealing based approach.
My approach would be:
Initialize listA and listB to a random state
With probability p run greedy step, otherwise run a random step
Keep track of the state and corresponding error (with a HashMap)
Greedy step: Find one element you can move between the list that optimizes the error.
Random Step: Pick a random element from either of these two sets and calculate the error. If the error is better, keep it. Otherwise with probability of q keep it.
At either of these two steps make sure that the new state is not already explored (or at least discourage it).
Set p to a small value (<0.1) and q could depend on the error difference.

Need help understanding recursion with array sorts

My task is to write a recursive method called quadSort that splits an array into 4 parts which are sorted by quadSort then the first two (A and B) are merged into one array (X) and the second two (C and D) are merged into one (Y) then those two are merged into one. The quadSort should call quadSort() 4 times (once for each part). My problem is that I have the base case completed but I can't figure out how to write the recursive portion of the method. Can anyone help me understand how to go about this or show me an example? Thanks in advance.
Edit: Here is my attempt
public static void quadSort(int array[], int index, int length){
for (int i = 1; i<array.length; i++){
if(array[i] <= 1000){
for(i = 1; i<array.length;i++){ //Start point for the insertion sort
int key = array[i];
int j = i-1;
while((i>-1) && (array[j] > key)){
array [j+1] = array[j];
i--;
}
array[j+1] = key;
} //End insertion sort
}
else{
int split = (array[i])/4;
}
}
return;
}
This is a weirdly modified mergeSort, where rather than recursing all the way until you get 1-length sub-arrays, and only then starting to merge, you recurse until the sub-array length is 1/4 of the original array length, sort that with whatever sorting algo you'd prefer (quicksort?) and then merge it back up. It is not clear what it is expected if the array does not have at least 4 elements. You can adjust it to whatever you need it to do in that case.
Using pseudocode it would be something like this:
quadSort(array, l, r):
m = array.length/2 - 1
//First checking if it is the base case
// i.e. l and r define one quarter of the array
if((l == 0 AND r < m) OR //First quarter
(l > 0 AND r == m) OR //Second quarter
(l == m+1 AND r < array.length - 1) OR //Third quarter
(l > m+1 AND r == array.length - 1)) //Fourth quarter
quicksort(array, l, r) //Base case
else
//Not the base case, hence we proceed to further split the array
//and recurse on quadsort, before proceeding to merge
m = (r+l)/2
quadsort(array, l, m)
quadsort(array, m+1, r)
merge(array, l, m , r)
merge(array, l, m, r):
//Standard merge procedure from mergesort

Selection: Median of medians

As a homework I was assigned to write algorithm that finds k-th ordered number from unordered set of numbers. As an approach, algorithm median of medians has been presented.
Unfortunately, my attemp has failed. If anyone spots a mistake - please correct me.
private int find(int[] A, int size, int k) {
if (size <= 10) {
sort(A, 0, size);
return A[k];
} else {
int[] M = new int[size/5];
for (int i = 0; i < size / 5; i++) {
sort(A, i*5, (i+1) * 5);
M[i] = A[i*5 + 2];
}
int m = find(M, M.length, M.length / 2);
int[] aMinus = new int[size];
int aMinusIndex = 0;
int[] aEqual = new int[size];
int aEqualIndex = 0;
int[] aPlus = new int[size];
int aPlusIndex = 0;
for (int j = 0; j < size; j++) {
if (A[j] < m) {
aMinus[aMinusIndex++] = A[j];
} else if (A[j] == m) {
aEqual[aEqualIndex++] = A[j];
} else {
aPlus[aPlusIndex++] = A[j];
}
}
if (aMinusIndex <= k) {
return find(aMinus, aMinusIndex, k);
} else if (aMinusIndex + aEqualIndex <= k) {
return m;
} else {
return find(aPlus, aPlusIndex, k - aMinusIndex - aEqualIndex);
}
}
}
private void sort(int[] t, int begin, int end) { //simple insertion sort
for (int i = begin; i < end; i++) {
int j = i;
int element = t[i];
while ((j > begin) && (t[j - 1] > element)) {
t[j] = t[j - 1];
j--;
}
t[j] = element;
}
}
The test I'm running is to put numbers {200, 199, 198, ..., 1) and get 1st number from ordered array. I'm getting:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -13
Which is thrown at return A[k] line, because of recursive call:
return find(aPlus, aPlusIndex, k - aMinusIndex - aEqualIndex);
Your branching logic for the recursion step is backwards. You're trying to find the kth smallest number, and you've found that there are aMinusIndex numbers smaller than m, aEqualIndex equal to m, and aPlusIndex larger than m.
You should be searching in aMinus if aMinusIndex >= k, not if aMinusIndex <= k -- and so on.
(See this easily by looking at the extreme case: say there are zero numbers smaller than m. Then clearly you should not be searching for anything in an empty array, but because 0 <= k, you will be.)
I don't know exactly what your problem is, but you definitely should not be doing this:
sort(A, i*5, (i+1) * 5);
Also, you shouldn't do so much copying, you don't gain any performance when you do that. The algorithm is supposed to be done in place.
Check this wikipedia: Selection algorithm
I understand that this is homework, so your options might be constrained, but I don't see how the Median of Medians is all that useful here. Just sort the entire array using a standard algorithm, and pick the kth element. Median of medians helps find a very good pivot for the sort. For data of 200 length, you aren't going to save much time.
So far as I know, you can't accurately obtain a median, or a percentile, or the kth element, without ultimately sorting the entire input array. Using subsets yields an estimate. If this is wrong, I'd really like to know, as I recently worked on code to find percentiles in arrays of millions of numbers!
p.s. it could be that I don't completely understand your code...

review of a codility test - pair_sum_even_count

I recently took an online test on codility as part of a recruitment process. I was given two simple problems to solve in 1 hour. For those who don't know codility, its an online coding test site where you can solve ACM style problems in many different languages.
If you have 30 or so mins then check this http://codility.com/demo/run/
My weapon of choice is usually Java.
So, one of the problems I have is as follows (I will try to remember, should have taken a screenshot)
Lets say you have array A[0]=1 A[1]=-1 ....A[n]=x
Then what would be the smartest way to find out the number of times when A[i]+A[j] is even where i < j
So if we have {1,2,3,4,5}
we have 1+3 1+5 2+4 3+5 = 4 pairs which are even
The code I wrote was some thing along the lines
int sum=0;
for(int i=0;i<A.length-1;i++){
for (int j=i+1;j<A.length;j++){
if( ((A[i]+A[j])%2) == 0 && i<j) {
sum++;
}
}
}
There was one more restriction that if the number of pairs is greater than 1e9 then it should retrun -1, but lets forget it.
Can you suggest a better solution for this. The number of elements won't exceed 1e9 in normal cases.
I think I got 27 points deducted for the above code (ie it's not perfect). Codility gives out a detailed assessment of what went wrong, I don't have that right now.
The sum of two integers is even if and only if they are either both even or both odd. You can simply go through the array and count evens and odds. The number of possibilities to combine k numbers from a set of size N is N! / ((N - k)! · k!). You just need to put the number of evens/odds as N and 2 as k. For this, the above simplifies to (N · (N - 1)) / 2. All the condition i < j does is to specify that each combination counts only once.
You can find the sum without calculating every pair individually.
A[i]+A[j] is even if A[i] is even and A[j] is even; or A[i] is odd and A[j] is odd.
A running total of odd and even numbers up to j can be kept, and added to sum depending on whether A[j] is odd or even:
int sum = 0;
int odd = 0;
int even = 0;
for(int j = 0; j < A.length; j++) {
if(A[j] % 2 == 0) {
sum += even;
even++;
} else {
sum += odd;
odd++;
}
}
Edit:
If you look at A={1,2,3,4,5}, each value of j would add the number of pairs with A[j] as the second number.
Even values:
A[j]=2 - sum += 0
A[j]=4 - sum += 1 - [2+4]
Odd values:
A[j]=1 - sum += 0
A[j]=3 - sum += 1 - [1+3]
A[j]=5 - sum += 2 - [1+5, 3+5]
Please check this
if (A == null || A.length < 2) {
return 0;
}
int evenNumbersCount = 0;
int oddNumberCount = 0;
for (int aA : A) {
if (aA % 2 == 0) {
evenNumbersCount++;
} else {
oddNumberCount++;
}
}
int i = (evenNumbersCount * (evenNumbersCount - 1)) / 2 + (oddNumberCount * (oddNumberCount - 1)) / 2;
return i > 1000000000 ? -1 : i;
If someone has a problem with understanding what Sante said here is another explanation:
Only odd+odd and even+even gives even. You have to find how many even and odd numbers are there. When you have it imagine that this as a problem with a meeting. How many people distinkt pairs are in the odd numbers list and even numbers list. This is the same problem as how many pairs will say hallo to each other at the party. This is also the number of edges in full graph. The answer is n*(n-1)/2 because there are n people, and you have to shake n-1 peoples hands and divide by 2 because the other person cant count your shake as distinct one. As you have here two separate "parties" going on you have to count them independently.
It's very simple
First you need to find the number of odds and even number in collection.
eg. x is odd if x&1 ==1, even otherwise,
if you have this, knowing that adding two even or two odds to each you get even.
You need to calc the sum of Combinations of two elements from Even numbers and Odd numbers.
having int A[] = {1,2,3,4,5};
int odds=0, evens=0;
for (int i=0; i< A.length; ++i)
{
if (A[i]&1==1) odds++;
else evens++;
}
return odds*(odds-1)/2 + evens*(evens-1)/2;
// Above goes from fact that the number of possibilities to combine k numbers from a set of size N is N! / ((N - k)! · k!). For k=2 this simplifies to (N · (N - 1)) / 2
See this answer also
int returnNumOFOddEvenSum(int [] A){
int sumOdd=0;
int sumEven=0;
if(A.length==0)
return 0;
for(int i=0; i<A.length; i++)
{
if(A[i]%2==0)
sumEven++;
else
sumOdd++;
}
return factSum(sumEven)+factSum(sumOdd);
}
int factSum(int num){
int sum=0;
for(int i=1; i<=num-1; i++)
{
sum+=i;
}
return sum;
}
public int getEvenSumPairs(int[] array){
int even=0;
int odd=0;
int evenSum=0;
for(int j=0; j<array.length; ++j){
if(array[j]%2==0) even++;
else odd++;
}
evenSum=((even*(even-1)/2) + (odd *(odd-1)/2) ;
return evenSum;
}
A Java implementation that works great based on the answer by "Svante":
int getNumSumsOfTwoEven(int[] a) {
long numOdd = 0;
long numEven = 0;
for(int i = 0; i < a.length; i++) {
if(a[i] % 2 == 0) { //even
numOdd++;
} else {
numEven++;
}
}
//N! / ((N - k)! · k!), where N = num. even nums or num odd nums, k = 2
long numSumOfTwoEven = (long)(fact(numOdd) / (fact(numOdd - 2) * 2));
numSumOfTwoEven += (long)(fact(numEven) / (fact(numEven - 2) * 2));
if(numSumOfTwoEven > ((long)1e9)) {
return -1;
}
return numSumOfTwoEven;
}
// This is a recursive function to calculate factorials
long fact(int i) {
if(i == 0) {
return 1;
}
return i * fact(i-1);
}
Algorithms are boring, here is a python solution.
>>> A = range(5)
>>> A
[0, 1, 2, 3, 4]
>>> even = lambda n: n % 2 == 0
>>> [(i, j) for i in A for j in A[i+1:] if even(i+j)]
[(0, 2), (0, 4), (1, 3), (2, 4)]
I will attempt another solution using vim.
You can get rid of the if/else statement and just have the following:
int pair_sum_v2( int A[], int N ) {
int totals[2] = { 0, 0 };
for (int i = 0; i < N; i++ ) {
totals[ A[i] & 0x01 ]++;
}
return ( totals[0] * (totals[0]-1) + totals[1] * (totals[1]-1) ) / 2;
}
Let count odd numbers as n1 and count even numbers as n2.
The sum of Pair(x,y) is even, only if we choose both x and y from the set of even numbers or both x and y from odd set (selecting x from even set and y from odd set or vice-versa will always result in the pair's sum to be an odd number).
So total combination such that each pair's sum is even = n1C2 + n2C2.
= (n1!) / ((n1-2)! * 2!) + (n2!) / ((n2-2)! * 2!)
= (n1 * (n1 - 1)) / 2 + (n2 * (n2 - 1)) / 2
--- Equation 1.
e.g : let the array be like: {1,2,3,4,5}
number of even numbers = n1 = 2
number of odd numbers = n2 = 2
Total pair such that the pair's sum is even from equation: 1 = (2*1)/2 + (3*2)/2 = 4
and the pairs are: (1,3), (1,5), (2,4), (3,5).
Going by traditional approach of adding and then checking might result in an integer overflow in programming on both positive as well as on negative extremes.
This is some pythonic solution
x = [1,3,56,4,3,2,0,6,78,90]
def solution(x):
sumadjacent = [x[i]+x[i+1] for i in range(len(x)-1) if x[i] < x[i+1]]
evenpairslist = [ True for j in sumadjacent if j%2==0]
return evenpairslist
if __name__=="__main__":
result=solution(x)
print(len(result))
int total = 0;
int size = A.length;
for(int i=0; i < size; i++) {
total += (A[size-1] - A[i]) / 2;
}
System.out.println("Total : " + total);

Categories

Resources