RosettaCodeData/Task/Sum-to-100/Java/sum-to-100.java

169 lines
5.1 KiB
Java

/*
* RossetaCode: Sum to 100, Java 8.
*
* Find solutions to the "sum to one hundred" puzzle.
*/
package rosettacode;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class SumTo100 implements Runnable {
public static void main(String[] args) {
new SumTo100().run();
}
void print(int givenSum) {
Expression expression = new Expression();
for (int i = 0; i < Expression.NUMBER_OF_EXPRESSIONS; i++, expression.next()) {
if (expression.toInt() == givenSum) {
expression.print();
}
}
}
void comment(String commentString) {
System.out.println();
System.out.println(commentString);
System.out.println();
}
@Override
public void run() {
final Stat stat = new Stat();
comment("Show all solutions that sum to 100");
final int givenSum = 100;
print(givenSum);
comment("Show the sum that has the maximum number of solutions");
final int maxCount = Collections.max(stat.sumCount.keySet());
int maxSum;
Iterator<Integer> it = stat.sumCount.get(maxCount).iterator();
do {
maxSum = it.next();
} while (maxSum < 0);
System.out.println(maxSum + " has " + maxCount + " solutions");
comment("Show the lowest positive number that can't be expressed");
int value = 0;
while (stat.countSum.containsKey(value)) {
value++;
}
System.out.println(value);
comment("Show the ten highest numbers that can be expressed");
final int n = stat.countSum.keySet().size();
final Integer[] sums = stat.countSum.keySet().toArray(new Integer[n]);
Arrays.sort(sums);
for (int i = n - 1; i >= n - 10; i--) {
print(sums[i]);
}
}
private static class Expression {
private final static int NUMBER_OF_DIGITS = 9;
private final static byte ADD = 0;
private final static byte SUB = 1;
private final static byte JOIN = 2;
final byte[] code = new byte[NUMBER_OF_DIGITS];
final static int NUMBER_OF_EXPRESSIONS = 2 * 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3;
Expression next() {
for (int i = 0; i < NUMBER_OF_DIGITS; i++) {
if (++code[i] > JOIN) {
code[i] = ADD;
} else {
break;
}
}
return this;
}
int toInt() {
int value = 0;
int number = 0;
int sign = (+1);
for (int digit = 1; digit <= 9; digit++) {
switch (code[NUMBER_OF_DIGITS - digit]) {
case ADD:
value += sign * number;
number = digit;
sign = (+1);
break;
case SUB:
value += sign * number;
number = digit;
sign = (-1);
break;
case JOIN:
number = 10 * number + digit;
break;
}
}
return value + sign * number;
}
@Override
public String toString() {
StringBuilder s = new StringBuilder(2 * NUMBER_OF_DIGITS + 1);
for (int digit = 1; digit <= NUMBER_OF_DIGITS; digit++) {
switch (code[NUMBER_OF_DIGITS - digit]) {
case ADD:
if (digit > 1) {
s.append('+');
}
break;
case SUB:
s.append('-');
break;
}
s.append(digit);
}
return s.toString();
}
void print() {
print(System.out);
}
void print(PrintStream printStream) {
printStream.format("%9d", this.toInt());
printStream.println(" = " + this);
}
}
private static class Stat {
final Map<Integer, Integer> countSum = new HashMap<>();
final Map<Integer, Set<Integer>> sumCount = new HashMap<>();
Stat() {
Expression expression = new Expression();
for (int i = 0; i < Expression.NUMBER_OF_EXPRESSIONS; i++, expression.next()) {
int sum = expression.toInt();
countSum.put(sum, countSum.getOrDefault(sum, 0) + 1);
}
for (Map.Entry<Integer, Integer> entry : countSum.entrySet()) {
Set<Integer> set;
if (sumCount.containsKey(entry.getValue())) {
set = sumCount.get(entry.getValue());
} else {
set = new HashSet<>();
}
set.add(entry.getKey());
sumCount.put(entry.getValue(), set);
}
}
}
}