From ab35275f17d199765a0eee89782303b67956570a Mon Sep 17 00:00:00 2001 From: Christopher Bohn <bohn@unl.edu> Date: Fri, 17 Dec 2021 22:24:33 -0600 Subject: [PATCH] Day 14 complete --- 2021/README.md | 12 ++- .../java/edu/unl/cse/bohn/year2021/Day14.java | 97 +++++++------------ 2 files changed, 45 insertions(+), 64 deletions(-) diff --git a/2021/README.md b/2021/README.md index b5d150c..c38c2a6 100644 --- a/2021/README.md +++ b/2021/README.md @@ -201,8 +201,14 @@ everything: memory management was definitely a HUGE constant factor. Keeping track of the positions of each element in the polymer will use very, very little memory. -Yup, this has definitely slowed down computation. And, now that I think about it, -I have to create as many indices as the original string's length was. This isn't -a savings. At. All. +Yup, this has definitely slowed down computation. And, now that I think about +it, I have to create as many indices as the original string's length was. This +isn't a savings. At. All. What am I missing? + +Let's try it this way: I don't need to keep track of the molecule *at all*. If +I keep track of the number of occurrences of each pair, then the numbers of +occurrences will grow and shrink in each iteration. + +Yup. That did it. diff --git a/2021/src/main/java/edu/unl/cse/bohn/year2021/Day14.java b/2021/src/main/java/edu/unl/cse/bohn/year2021/Day14.java index 6cc4c91..f0edcb9 100644 --- a/2021/src/main/java/edu/unl/cse/bohn/year2021/Day14.java +++ b/2021/src/main/java/edu/unl/cse/bohn/year2021/Day14.java @@ -3,14 +3,14 @@ package edu.unl.cse.bohn.year2021; import edu.unl.cse.bohn.Puzzle; import java.util.HashMap; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; @SuppressWarnings("unused") public class Day14 extends Puzzle { - private Map<String, Character> rules; + private Map<String, String> rules; + private Map<String, AtomicLong> patterns; public Day14(boolean isProductionReady) { super(isProductionReady); @@ -38,78 +38,53 @@ public class Day14 extends Puzzle { private String parseData(List<String> data) { String initialMolecule = data.get(0); rules = new HashMap<>(); + patterns = new HashMap<>(); for (String rule : data) { if (rule.contains(" -> ")) { String[] halves = rule.split(" -> "); - rules.put(halves[0], halves[1].charAt(0)); + rules.put(halves[0], halves[1]); + patterns.put(halves[0], new AtomicLong(0L)); } } + for (int i = 0; i < initialMolecule.length() - 1; i++) { + patterns.get(initialMolecule.substring(i, i + 2)).getAndIncrement(); + } return initialMolecule; } private long producePolymer(List<String> data, int numberOfSteps) { - Map<Character, List<AtomicLong>> molecule = new HashMap<>(); - long index = 0; - for (char element : parseData(data).toCharArray()) { - if (!molecule.containsKey(element)) { - molecule.put(element, new LinkedList<>()); - } - molecule.get(element).add(new AtomicLong(index++)); - } - for (char element : molecule.keySet()) { - System.out.println("\t\t" + element + ": " + molecule.get(element)); - } + String molecule = parseData(data); + String tail = molecule.substring(molecule.length() - 2); + Map<String, Long> newValues = new HashMap<>(); for (int i = 0; i < numberOfSteps; i++) { - System.out.println("\tGrowing...\t" + i); - growMolecule(molecule); - if (i < 4) { - for (char element : molecule.keySet()) { - System.out.println("\t\t" + element + ": " + molecule.get(element)); - } + for (String pattern : patterns.keySet()) { + newValues.put(pattern, 0L); } - } - long leastFrequentOccurrence = molecule.keySet().stream() - .mapToLong(element -> molecule.get(element).size()).min().orElseThrow(); - long mostFrequentOccurrence = molecule.keySet().stream() - .mapToLong(element -> molecule.get(element).size()).max().orElseThrow(); - return mostFrequentOccurrence - leastFrequentOccurrence; - } - - private Character getCharAt(Map<Character, List<AtomicLong>> molecule, long index) { - return molecule.keySet().stream() - .filter(e -> molecule.get(e).stream().anyMatch(position -> position.get() == index)) - .findFirst().orElse(null); - } - - private void incrementIndicesAfter(Map<Character, List<AtomicLong>> molecule, long start) { - for (char element : molecule.keySet()) { - molecule.get(element).stream() - .filter(position -> start <= position.get()) - .forEach(AtomicLong::getAndIncrement); - } - } - - @SuppressWarnings("UnusedReturnValue") - private Map<Character, List<AtomicLong>> growMolecule(Map<Character, List<AtomicLong>> molecule) { - boolean stillGrowing = true; - long index = 0; - char[] pattern = {getCharAt(molecule, index), getCharAt(molecule, ++index)}; - do { - incrementIndicesAfter(molecule, index); - char newElement = rules.get(new String(pattern)); - if (!molecule.containsKey(newElement)) { - molecule.put(newElement, new LinkedList<>()); + for (String pattern : patterns.keySet()) { + String newPattern = pattern.charAt(0) + rules.get(pattern); + newValues.put(newPattern, newValues.get(newPattern) + patterns.get(pattern).longValue()); + newPattern = rules.get(pattern) + pattern.charAt(1); + newValues.put(newPattern, newValues.get(newPattern) + patterns.get(pattern).longValue()); } - molecule.get(newElement).add(new AtomicLong(index++)); - Character nextElement = getCharAt(molecule, ++index); - if (nextElement == null) { - stillGrowing = false; - } else { - pattern[0] = pattern[1]; - pattern[1] = nextElement; + for (String pattern : patterns.keySet()) { + patterns.get(pattern).set(newValues.get(pattern)); } - } while (stillGrowing); - return molecule; + tail = rules.get(tail) + tail.charAt(1); + } + Map<Character, AtomicLong> elementCounts = new HashMap<>(); + elementCounts.put(tail.charAt(1), new AtomicLong(1L)); + for (String pattern : patterns.keySet()) { + char element = pattern.charAt(0); + if (!elementCounts.containsKey(element)) { + elementCounts.put(element, new AtomicLong(0L)); + } + elementCounts.get(element).getAndAdd(patterns.get(pattern).longValue()); + } + long leastCommon = elementCounts.keySet().stream() + .mapToLong(element -> elementCounts.get(element).longValue()).min().orElseThrow(); + long mostCommon = elementCounts.keySet().stream() + .mapToLong(element -> elementCounts.get(element).longValue()).max().orElseThrow(); + return mostCommon - leastCommon; } @Override -- GitLab