Мои взаимоотношения с этой загадкой можно описать примерно такой фразой (по мотивам анекдотов):
– Дерево – подумал Штирлиц
– Дерево – поняло дерево
Всё началось с того, что мне совершенно не хотелось строить это дерево (забегая вперёд – всё же пришлось).
После пары неудачных попыток (о которых ниже) – решил хранить эту псевдо-ФС в избыточном виде – получились этакие “мангровые заросли”.
Директории, помимо вложенности в свои родительские каталоги, дублируются на корневом уровне. Таким образом получается без лишних усилий посчитать результат по условиям загадки.
record File(String name, long size, List<File> files) {}
static Map<String, File> flattenFs = new HashMap<>();
static void day7(String puzzleInputUri) throws IOException, InterruptedException {
List<String[]> commands = client.send(
request.uri((URI.create(puzzleInputUri))).build(), HttpResponse.BodyHandlers.ofLines()
).body()
.skip(1)
.filter(line -> !line.equals("$ ls"))
.map(line -> line.replace("$ ", ""))
.map(line -> line.split(" "))
.toList();
String currentDirKey = "/";
flattenFs.put(currentDirKey, new File("/", 0L, new ArrayList<>()));
for (var commandLine : commands) {
String command = commandLine[0];
String arg = commandLine[1];
if ("dir".equals(command)) {
String newDirKey = currentDirKey + "/" + arg;
flattenFs.putIfAbsent(newDirKey, new File(newDirKey, 0L, new ArrayList<>()));
flattenFs.get(currentDirKey).files().add(flattenFs.get(newDirKey));
} else if ("cd".equals(command)) {
if ("..".equals(arg)) {
String parentDir = currentDirKey.substring(0, currentDirKey.lastIndexOf("/"));
currentDirKey = flattenFs.keySet().stream()
.filter(dir -> dir.equals(parentDir))
.findAny().orElseThrow();
} else {
currentDirKey += "/" + arg;
}
} else {
flattenFs.get(currentDirKey).files().add(new File(arg, Long.parseLong(command), new ArrayList<>()));
}
}
long resultPartOne = flattenFs.values().stream()
.mapToLong(dir -> getTotalSize(dir, 0L))
.filter(size -> size <= 100_000L)
.sum();
System.out.println(resultPartOne);
long usedSpace = getTotalSize(flattenFs.get("/"), 0L);
long freeSpace = 70_000_000L - usedSpace;
long needForUpdateSpace = 30_000_000L - freeSpace;
long resultPartTwo = flattenFs.values().stream()
.mapToLong(dir -> getTotalSize(dir, 0L))
.filter(size -> size >= needForUpdateSpace)
.min()
.orElseThrow();
System.out.println(resultPartTwo);
}
static long getTotalSize(File dir, long totalSize) {
List<File> files = dir.files();
for (File file : files) {
totalSize += file.size() > 0L
? file.size()
: getTotalSize(flattenFs.get(file.name()), 0L);
}
return totalSize;
}
Этот пример запускал на Java 17, на традиционно используемой в прошлых задачах одиннадцатой версии Java он не заработает.
Исходные данные: https://adventofcode.com/2022/day/7/inputЧитать далее Advent of Code 2022: Day 7