My question is about the CodeFu practice problem (problem 3 rounds 2 rounds). Basically it comes down to splitting the array of integers into two (almost) equal halves and returning the smallest possible difference between them. I have included a description of the problem below. As noted in the comments, this can be described as a problem of a balanced section , which is a problem in the field of dynamic programming .
Now similar problems have been discussed a lot, but I could not find an effective solution for this particular one. The problem, of course, is that the number of possible combinations for moving in the near future is too large to search for brute force (at least when using recursion). I have a recursive solution that works great for everyone except the largest task sets. I tried to add some optimizations that stop recursion earlier, but the performance is still too slow to solve some arrays of maximum length (30) within the 5 second maximum allowed by CodeFu. Any suggestions on how to improve or rewrite the code would be very welcome. I would also like to know if the iterative version can do this.
Update: on this wonderful site there is a theoretical discussion of the problem of a balanced partition, which gives a good idea on how to do this and solve it dynamically. This is what I do, but I donβt know how to apply the theory correctly. The film mentions that elements in two subcollections can be found "using the old backtick trick", but I donβt see how.
Problem
You and your friend have several coins with different amounts. You need to divide the coins into two groups so that the difference between these groups is minimal.
eg. Coins of sizes 1,1,1,3,5,10,18 can be divided as: 1,1,1,3,5 and 10,18 1,1,1,3,5,10 and 18 or 1,1, 3,5,10 and 1,18 The third combination is favorable, since in this case the difference between the groups is only 1. Restrictions: coins will have from 2 to 30 elements, including each element of coins, will be between 1 and 100000 inclusive
Return value: the minimum difference is possible when the coins are divided into two groups
NOTE. The CodeFu rules state that the runtime on the CodeFu server can be no more than 5 seconds.
Main code
Arrays.sort(coins); lower = Arrays.copyOfRange(coins, 0,coins.length-1); //(after sorting) put the largest element in upper upper = Arrays.copyOfRange(coins, coins.length-1,coins.length); smallestDifference = Math.abs(arraySum(upper) - arraySum(lower)); return findSmallestDifference(lower, upper, arraySum(lower), arraySum(upper), smallestDifference);
Recursion code
private int findSmallestDifference (int[] lower, int[] upper, int lowerSum, int upperSum, int smallestDifference) { int[] newUpper = null, newLower = null; int currentDifference = Math.abs(upperSum-lowerSum); if (currentDifference < smallestDifference) { smallestDifference = currentDifference; } if (lowerSum < upperSum || lower.length < upper.length || lower[0] > currentDifference || lower[lower.length-1] > currentDifference || lower[lower.length-1] < upper[0]/lower.length) { return smallestDifference; } for (int i = lower.length-1; i >= 0 && smallestDifference > 0; i--) { newUpper = addElement(upper, lower[i]); newLower = removeElementAt(lower, i); smallestDifference = findSmallestDifference(newLower, newUpper, lowerSum - lower[i], upperSum + lower [i], smallestDifference); } return smallestDifference; }
Data set
Here is an example kit that takes too long to solve.
{100000,60000,60000,60000,60000,60000,60000,60000,60000, 60000,60000,60000,60000,60000,60000,60000,60000,60000, 60,000,60000,60000,60000,60000,60000,60000 , 60000,60000, 60000,60000,60000}
If you need all the source code, I put it on Ideone .