I asked this question and I have made enough changes, so I think it deserves a new question.
The Problem:
A triangle needs a good foundation. Every row in the triangle is derived from the sum of the two values below it. However, there can be no repeated values, if a value shows up more than once the triangle crumbles. Find the base which minimises the value in the top of the triangle satisfying the condition of no duplicates.
Example:
20 8 12 [3] 5 7 1 2 [3] 4
Here 3 occurs twice, so the triangle is considered invalid
Suggestions:
I would like ideas focused on
- Performance; base size 5 takes about 200 milliseconds on my machine, a base of 6 takes about 40 seconds, and 7 is still running after half an hour.
- Readability; how difficult is it to read the code
import java.util.*;
public class SmallestTriangle {
static int[][] pascal = {
{},
{ 1 },
{ 1, 1 },
{ 1, 2, 1 },
{ 1, 3, 3, 1 },
{ 1, 4, 6, 4, 1 },
{ 1, 5, 10, 10, 5, 1 },
{ 1, 6, 15, 20, 15, 6, 1 },
{ 1, 7, 21, 35, 35, 21, 7, 1 },
{ 1, 8, 28, 56, 70, 56, 28, 8, 1 },
{ 1, 9, 36, 84, 126, 126, 84, 36, 9, 1 },
{ 1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1 }
};
public static void main(String[] args) {
long start = System.nanoTime();
SmallestTriangle solver = new SmallestTriangle();
int baseSize = 6;
solver.findBestTriangle(baseSize); //run
System.out.println("Took: " + (System.nanoTime() - start) / 1000000 + "ms");
}
void findBestTriangle(int aBaseSize) {
int bestFound = 1000;
int currentResult = bestFound;
int[] bestTriangleFound = new int[aBaseSize];
int[] currentArray = new int[aBaseSize];
for (int a = 0; a < aBaseSize; a++) {
currentArray[a] = a + 1;
}
while (currentArray[0] < bestFound) { //run until the first number in the count is equal to the best score, needs improvement
currentResult = checkTriangle(currentArray, bestFound);
if (currentResult >= 0 && currentResult < bestFound) {
bestFound = currentResult;
bestTriangleFound = Arrays.copyOf(currentArray, currentArray.length);
System.out.println(Arrays.toString(bestTriangleFound) + ":\t" + bestFound);
}
currentArray = nextTry(currentArray, bestFound);
}
System.out.println("The smallest result possible is: " + bestFound);
System.out.println(Arrays.toString(bestTriangleFound));
}
/* returns the next base to try, it takes the previous base, adds 1 to the end, then checks each number for overflow
(overflow occurs if it passes the best found triangle so far)
*/
int[] nextTry(int[] aTriangleBase, int aOverflowLimit) {
int size = aTriangleBase.length;
aTriangleBase[size - 1]++;
int sum = aTriangleBase[size -1];
for (int a = size - 1; a > 0; --a) {
int c = pascal[size][a] * aTriangleBase[a];
if (c >= aOverflowLimit) {
aTriangleBase[a] = 1;
aTriangleBase[a - 1]++;
}
sum += pascal[size][a-1] * aTriangleBase[a-1];
}
return aTriangleBase;
}
/** A method to check whether a base for a triangle will form a valid triangle
@param int[] aTriangleBase a potential triangle base
@param int aLimit a limit that if passed, guarentees the base is not the smallest
@return int -1 <= x < aLimit if invalid, returns -1, otherwise it returns the top number in the triangle, the triangle's score
*/
int checkTriangle(int[] aTriangleBase, int aLimit) {
int size = aTriangleBase.length;
boolean[] count = new boolean[aLimit];
// check input for duplicates
for (int i : aTriangleBase) {
if (count[i])
return -1;
count[i] = true;
}
int[] firstRow = new int[size];
int[] secondRow = Arrays.copyOf(aTriangleBase, size);
boolean useFirst = true;
int a = 0;
for(int i = 1; i < size; ++i) {
if(useFirst) {
for(int j = 0; j < size-i; ++j) {
a = secondRow[j] + secondRow[j + 1];
if (a >= aLimit || count[a])
return -1;
count[a] = true;
firstRow[j] = a;
}
useFirst = false;
} else {
for(int j = 0; j < size-i; ++j) {
a = firstRow[j] + firstRow[j + 1];
if (a >= aLimit || count[a])
return -1;
count[a] = true;
secondRow[j] = a;
}
useFirst = true;
}
}
// return final value, our result if no duplicates occur during the process
return a;
}
}