I am doing the following programming exercise: Stone pile. The statement is:
You are given pile of stones with different weights.
Your task is to divide this stone pile into two parts, so the weight difference between the piles will be minimal. You can't break one stone into smaller ones.
For example if we have stones:
[1, 2, 3, 4]
We could divide them into:
[2, 3], [1, 4]
So the difference will be 0
If you are given empty stone pile, you can still divide it into two piles with no stones.
The pile will contain maximum 22 stones.
Following the examples I have thought:
Sort stones in ascending order
for each stone
if length is even
if movement is even
add min and max to right list
remove them
if movement is odd
add min and max to left list
remove them
if length is odd
if movement is even
add max to left
remove it
if movement is odd
add min to right
remove it
if there are more items
add next min
remove it
So in code would be:
import java.util.*;
import java.util.stream.*;
public class Pile {
public static int minDiff(int[] stones) {
System.out.println("stones: "+Arrays.toString(stones));
Arrays.sort(stones);
System.out.println("stones: "+Arrays.toString(stones));
List<Integer> allStones = Arrays.stream(stones).boxed().collect(Collectors.toList());
System.out.println("allStones: "+Arrays.toString(allStones.toArray()));
ArrayList<Integer> left = new ArrayList<>();
ArrayList<Integer> right = new ArrayList<>();
for(int i = 0; allStones.size()>0; i++){
if(stones.length%2==0){
if(i%2==0){
right.add(allStones.get(0));
right.add(allStones.get(allStones.size()-1));
allStones.remove(0);
allStones.remove(allStones.size()-1);
}else{
left.add(allStones.get(0));
left.add(allStones.get(allStones.size()-1));
allStones.remove(0);
allStones.remove(allStones.size()-1);
}
}else{
if(i%2==0){
left.add(allStones.get(allStones.size()-1));
allStones.remove(allStones.size()-1);
}else{
right.add(allStones.get(0));
allStones.remove(0);
if(allStones.size()>0){
right.add(allStones.get(0));
allStones.remove(0);
}
}
}
}
System.out.println("left: "+Arrays.toString(left.toArray()));
System.out.println("right: "+Arrays.toString(right.toArray()));
return left.stream().mapToInt(Integer::intValue).sum()-right.stream().mapToInt(Integer::intValue).sum();
}
}
Currently it is just working when we test it with inputs where the difference is zero. However if we test it with other inputs, it will fail.
Given the following tests, the first suite will pass, the others fail:
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import org.junit.runners.JUnit4;
public class PersonTest {
@Test
public void testDifferenceShouldBeZero(){
assertEquals(0, Pile.minDiff(new int[]{1, 2, 3}));
assertEquals(0, Pile.minDiff(new int[]{1, 2, 3, 4}));
assertEquals(0, Pile.minDiff(new int[]{5,5,4,3,3}));
}
@Test
public void testDifferenceShouldBeOne(){
assertEquals(1, Pile.minDiff(new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22}));
}
@Test
public void testDifferenceShouldBeTwo(){
assertEquals(2, Pile.minDiff(new int[]{89409, 34351, 3065, 10128, 27694, 27585, 87350, 33875, 2658, 41606, 57512, 73368, 83345, 37048, 31827, 94644, 15972, 74813, 31441, 70395}));
}
}
For example, when stones are: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
Trace is:
stones: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
stones: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
allStones: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
left: [2, 21, 4, 19, 6, 17, 8, 15, 10, 13]
right: [1, 22, 3, 20, 5, 18, 7, 16, 9, 14, 11, 12]
Being the result:
expected:<1> but was:<-23>
How could we split the stone pile in two chunks where the difference is the minimum, for the general case?
We have read: