Skip to content

Commit 00b4f0a

Browse files
committed
Faster approach using sorted ranges for faster equality checking
1 parent fd32744 commit 00b4f0a

File tree

2 files changed

+47
-14
lines changed

2 files changed

+47
-14
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ Performance is reasonable even on older hardware, for example a 2011 MacBook Pro
381381
| 16 | [Aunt Sue](https://adventofcode.com/2015/day/16) | [Source](src/year2015/day16.rs) | 20 |
382382
| 17 | [No Such Thing as Too Much](https://adventofcode.com/2015/day/17) | [Source](src/year2015/day17.rs) | 45 |
383383
| 18 | [Like a GIF For Your Yard](https://adventofcode.com/2015/day/18) | [Source](src/year2015/day18.rs) | 154 |
384-
| 19 | [Medicine for Rudolph](https://adventofcode.com/2015/day/19) | [Source](src/year2015/day19.rs) | 187 |
384+
| 19 | [Medicine for Rudolph](https://adventofcode.com/2015/day/19) | [Source](src/year2015/day19.rs) | 23 |
385385
| 20 | [Infinite Elves and Infinite Houses](https://adventofcode.com/2015/day/20) | [Source](src/year2015/day20.rs) | 1667 |
386386
| 21 | [RPG Simulator 20XX](https://adventofcode.com/2015/day/21) | [Source](src/year2015/day21.rs) | 2 |
387387
| 22 | [Wizard Simulator 20XX](https://adventofcode.com/2015/day/22) | [Source](src/year2015/day22.rs) | 235 |

src/year2015/day19.rs

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
//! # Medicine for Rudolph
22
//!
3-
//! Part one is a brute force search and replace of every possibility.
3+
//! Part one is a brute force search and replace of every possibility with two optimizations.
4+
//! Replacements that add the same number of extra molecules are grouped together, as different
5+
//! length strings can never match.
6+
//!
7+
//! Next replacement ranges are sorted into ascending order. Non-overlapping ranges can never match,
8+
//! so checking for other equals string only needs to consider ranges that intersect.
49
//!
510
//! Part two uses the analysis from `askalski` provided on the
611
//! [Day 19 solution megathread](https://www.reddit.com/r/adventofcode/comments/3xflz8/day_19_solutions/).
@@ -15,29 +20,57 @@ pub fn parse(input: &str) -> Input<'_> {
1520

1621
pub fn part1(input: &Input<'_>) -> usize {
1722
let (molecule, replacements) = input;
18-
let mut distinct = FastSet::new();
1923

20-
for (from, to) in replacements {
21-
for (start, _) in molecule.match_indices(from) {
22-
let size = molecule.len() - from.len() + to.len();
23-
let end = start + from.len();
24+
let mut groups = FastMap::new();
25+
let mut modified = Vec::new();
26+
let mut result = 0;
2427

25-
let mut string = String::with_capacity(size);
26-
string.push_str(&molecule[..start]);
27-
string.push_str(to);
28-
string.push_str(&molecule[end..]);
28+
// Group replacements of the same size together.
29+
for &(from, to) in replacements {
30+
let extra = to.len() - from.len();
31+
groups.entry(extra).or_insert(Vec::new()).push((from, to));
32+
}
2933

30-
distinct.insert(string);
34+
for (_, group) in groups {
35+
// Build list of all possible modified strings.
36+
for (from, to) in group {
37+
for (start, _) in molecule.match_indices(from) {
38+
let end = start + from.len();
39+
modified.push((start, end, to));
40+
}
3141
}
42+
43+
modified.sort_unstable_by_key(|&(start, ..)| start);
44+
45+
'outer: for (i, &(start, end, to)) in modified.iter().enumerate() {
46+
for &(start2, _, to2) in &modified[i + 1..] {
47+
// Stop checking early once ranges no longer overlap.
48+
if start2 >= start + to.len() {
49+
break;
50+
}
51+
52+
// Compare replaced sections for equality.
53+
let first = to.bytes().chain(molecule[end..].bytes());
54+
let second = molecule[start..start2].bytes().chain(to2.bytes());
55+
56+
if first.zip(second).all(|(a, b)| a == b) {
57+
continue 'outer;
58+
}
59+
}
60+
61+
result += 1;
62+
}
63+
64+
modified.clear();
3265
}
3366

34-
distinct.len()
67+
result
3568
}
3669

3770
pub fn part2(input: &Input<'_>) -> usize {
3871
let (molecule, _) = input;
3972

40-
let elements = molecule.chars().filter(char::is_ascii_uppercase).count();
73+
let elements = molecule.bytes().filter(u8::is_ascii_uppercase).count();
4174
let rn = molecule.matches("Rn").count();
4275
let ar = molecule.matches("Ar").count();
4376
let y = molecule.matches('Y').count();

0 commit comments

Comments
 (0)