I am trying to solve a programming problem and I see the size of program has increased a bit while I keep coding. I found this problem here.
Here is the problem:
Write a program that outputs all possibilities to put + or - or nothing between the numbers 1, 2, ..., 9 (in this order) such that the result is always 100. For example: 1 + 2 + 34 – 5 + 67 – 8 + 9 = 100.
I coded it in Java.
Here is the complete program.
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
/**
* Write a program that outputs all possibilities to put + or -
* or nothing between the numbers 1, 2, ..., 9 (in this order)
* such that the result is always 100. For example: 1 + 2 + 34 – 5 + 67 – 8 + 9 = 100.
*/
/**
* @author srk
*/
public class Problem5 {
private final int START_INDEX = 0;
private final String LEFT_SQUARE_BRACE = "[";
private final String RIGHT_SQUARE_BRACE = "]";
private final String SPLIT_STRING_REGEX = ",";
private final String STRING_SUFFIX = ",";
private final List<String> OPERATIONS = Arrays.asList("+", "-", "");
public static void main(String[] args) {
Problem5 problem5 = new Problem5();
List<Integer> oneToNine = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
int resultantSum = 100;
/* Step 1: Break it into functions */
LinkedHashMap<String, List<StringBuilder>> fBreakUp = problem5
.breakIntoFunctions(new ArrayList<>(oneToNine),
new LinkedHashMap<String, List<StringBuilder>>());
/* Step2: Resolve each function from bottom up */
problem5.workFromBottomUp(problem5.fBreakUpKeysFrmTail(fBreakUp),
fBreakUp);
/*
* Step3: Evaluate all the combinations and fetch only those, whose sum
* is 100
*/
List<StringBuilder> allcombinations = fBreakUp.get(problem5
.getfunction(oneToNine));
System.out.println("Probable combinations -> " + allcombinations.size());
List<String> specCombinations = problem5.getSpecCombinations(
allcombinations, resultantSum);
problem5.printResult(specCombinations);
}
private void printResult(List<String> specCombinations) {
for (String combination : specCombinations) {
System.out.println(combination);
}
System.out.println("Total combinations " + specCombinations.size());
}
private List<String> getSpecCombinations(
List<StringBuilder> allcombinations, int resultantSum) {
List<String> finalCombi = new ArrayList<>();
for (StringBuilder csv : allcombinations) {
for (String thisCombi : csv.toString().split(SPLIT_STRING_REGEX)) {
if (findSum(thisCombi).compareTo(
BigInteger.valueOf(resultantSum)) == 0) {
finalCombi.add(thisCombi);
}
}
}
return finalCombi;
}
private static BigInteger findSum(String input) {
/* Step1 : Split with + */
String[] positives = input.split("[+]+");
List<BigInteger> ListAfterExpEval = new ArrayList<>();
for (String thisPosExp : positives) {
BigInteger expValue = BigInteger.ZERO;
if (thisPosExp.contains("-")) {
/* Split with -, if it has */
String[] negatives = thisPosExp.split("[-]+");
for (String thisNegExp : negatives) {
/* Covert String to BigInteger */
BigInteger thisNumber = new BigInteger(thisNegExp);
if (expValue == BigInteger.ZERO) {
expValue = thisNumber;
} else {
expValue = expValue.subtract(thisNumber);
}
}
ListAfterExpEval.add(expValue);
} else {
/* could be a number */
ListAfterExpEval.add(new BigInteger(thisPosExp));
}
}
BigInteger finalSum = BigInteger.ZERO;
for (BigInteger thisNum : ListAfterExpEval) {
if (finalSum == BigInteger.ZERO) {
finalSum = thisNum;
} else {
finalSum = finalSum.add(thisNum);
}
}
return finalSum;
}
private void workFromBottomUp(List<String> fBreakUpKeys,
LinkedHashMap<String, List<StringBuilder>> fBreakUp) {
String tailKeyInFBreakUp = fBreakUpKeys.remove(START_INDEX);
Iterator<String> fBreakUpKeysItr = fBreakUpKeys.iterator();
String keyBeforeTail;
while (fBreakUpKeysItr.hasNext()) {
keyBeforeTail = fBreakUpKeysItr.next();
fBreakUpKeysItr.remove();
tailKeyInFBreakUp = resolveFunctions(tailKeyInFBreakUp,
keyBeforeTail, fBreakUp);
}
}
private String resolveFunctions(String tailKeyInFBreakUp,
String keyBeforeTail,
LinkedHashMap<String, List<StringBuilder>> fBreakUp) {
List<StringBuilder> fValToBeSubstituted = fBreakUp
.get(tailKeyInFBreakUp);
List<StringBuilder> fValsToBeResolved = fBreakUp.get(keyBeforeTail);
for (StringBuilder fValToBeResolved : fValsToBeResolved) {
int indexOfF = fValToBeResolved.indexOf(tailKeyInFBreakUp);
if (indexOfF != -1) {
fValToBeResolved.replace(indexOfF, fValToBeResolved.length(),
fValToBeSubstituted.toString());
fValToBeResolved.replace(START_INDEX,
fValToBeResolved.length(),
cartesianProduct(fValToBeResolved));
}
}
fBreakUp.remove(tailKeyInFBreakUp);
return keyBeforeTail;
}
private String cartesianProduct(StringBuilder fValToBeResolved) {
StringBuilder localSb = new StringBuilder();
int indexOfLeftSqBrace = fValToBeResolved.indexOf(LEFT_SQUARE_BRACE);
int indexOfRightSqBrace = fValToBeResolved.indexOf(RIGHT_SQUARE_BRACE);
String prefix = fValToBeResolved.substring(START_INDEX,
indexOfLeftSqBrace);
List<String> resolvedVals = Arrays.asList(fValToBeResolved.substring(
indexOfLeftSqBrace + 1, indexOfRightSqBrace).split(
SPLIT_STRING_REGEX));
for (String val : resolvedVals) {
localSb.append(prefix.trim() + val.trim());
if (resolvedVals.indexOf(val) != resolvedVals.size() - 1) {
localSb.append(STRING_SUFFIX);
}
}
return localSb.toString();
}
private List<String> fBreakUpKeysFrmTail(
LinkedHashMap<String, List<StringBuilder>> fBreakUp) {
List<String> functionsBreakUpKeys = new ArrayList<>(fBreakUp.keySet());
Collections.reverse(functionsBreakUpKeys);
return functionsBreakUpKeys;
}
private LinkedHashMap<String, List<StringBuilder>> breakIntoFunctions(
List<Integer> workList,
LinkedHashMap<String, List<StringBuilder>> fBreakUp) {
String function = getfunction(workList);
String head = getHeadAndRemoveit(workList);
boolean workListSizeIsOne = workList.size() == 1 ? true : false;
ArrayList<StringBuilder> breakDownValues = new ArrayList<>();
for (String operation : OPERATIONS) {
StringBuilder sb = new StringBuilder();
if (!(workListSizeIsOne ? breakDownValues.add(sb.append(head
+ operation + workList.get(START_INDEX))) : breakDownValues
.add(sb.append(head + operation + getfunction(workList)))))
break;
}
fBreakUp.put(function, breakDownValues);
if (!workList.isEmpty() && !workListSizeIsOne)
breakIntoFunctions(workList, fBreakUp);
return fBreakUp;
}
private String getHeadAndRemoveit(List<Integer> workList) {
Integer headElement = workList.get(START_INDEX);
workList.remove(headElement);
return String.valueOf(headElement);
}
private String getfunction(List<Integer> list) {
StringBuilder sb = new StringBuilder("f(");
for (Integer integ : list) {
sb.append(integ);
}
return sb.append(")").toString();
}
}
What are the points, where it could be improved and optimized?