Skip to content

Commit 3d61f8a

Browse files
committed
Faster day 9
1 parent 26722d9 commit 3d61f8a

File tree

4 files changed

+72
-37
lines changed

4 files changed

+72
-37
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,6 @@ dhat-heap.json
2929

3030
data/timings.json
3131

32-
flamegraph.svg
32+
flamegraph.svg
33+
34+
*.log

1

Whitespace-only changes.

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www.
1919
| [Day 6](./src/bin/06.rs) | `48.5µs` | `4.2ms` |
2020
| [Day 7](./src/bin/07.rs) | `316.2µs` | `319.6µs` |
2121
| [Day 8](./src/bin/08.rs) | `7.4µs` | `15.5µs` |
22-
| [Day 9](./src/bin/09.rs) | `149.0µs` | `6.5ms` |
22+
| [Day 9](./src/bin/09.rs) | `157.2µs` | `2.0ms` |
2323
| [Day 10](./src/bin/10.rs) | `31.1µs` | `28.6µs` |
2424
| [Day 11](./src/bin/11.rs) | `71.0µs` | `766.0µs` |
2525
| [Day 12](./src/bin/12.rs) | `434.7µs` | `674.6µs` |
@@ -28,7 +28,7 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www.
2828
| [Day 15](./src/bin/15.rs) | `119.7µs` | `591.0µs` |
2929
| [Day 16](./src/bin/16.rs) | `158.9µs` | `202.6µs` |
3030

31-
**Total: 19.44ms**
31+
**Total: 14.95ms**
3232
<!--- benchmarking table --->
3333

3434
---

src/bin/09.rs

Lines changed: 67 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ fn parse_blocks(input: &str) -> Vec<Block> {
7575
} else {
7676
None
7777
};
78+
79+
if num == 0 {
80+
continue;
81+
}
82+
7883
let b = Block {
7984
file_id,
8085
length: num,
@@ -130,57 +135,78 @@ pub fn part_two(input: &str) -> Option<u64> {
130135
// we want to move the files in order of decreasing file ID number
131136
// if there is no span of free space to the left of a file that is large enough to fit the file, the file does not move
132137

133-
let mut spaces_block_indices: Vec<usize> = Vec::with_capacity(1000);
134-
for (i, b) in blocks.iter().enumerate() {
135-
if b.file_id.is_none() {
136-
spaces_block_indices.push(i);
137-
}
138-
}
138+
let mut spaces_block_indices_by_size: Vec<Vec<usize>> =
139+
(0..10).map(|_| Vec::with_capacity(500)).collect();
140+
141+
// store indices smaller last so we can pop from the end and don't need to shift that much
142+
blocks
143+
.iter()
144+
.enumerate()
145+
.rev()
146+
.filter(|(_, b)| b.file_id.is_none())
147+
.filter(|(_, b)| b.length > 0)
148+
.for_each(|(i, b)| {
149+
spaces_block_indices_by_size[b.length as usize].push(i);
150+
});
139151

140152
let mut right_block_idx = blocks.len() - 1;
141153
while right_block_idx > 0 {
142-
let right_block = &blocks[right_block_idx];
154+
let right_block = &blocks[right_block_idx].clone();
143155
if right_block.is_free() {
144156
right_block_idx -= 1;
145157
continue;
146158
}
147159

148-
// look for a free space block that can fit the file
149-
let mut free_space_block_idx = None;
150-
for (i, space_idx) in spaces_block_indices.iter().enumerate() {
151-
if *space_idx > right_block_idx {
152-
break;
153-
}
154-
let left_block = &blocks[*space_idx];
155-
if left_block.length > right_block.length {
156-
free_space_block_idx = Some(*space_idx);
157-
for i in i..spaces_block_indices.len() {
158-
spaces_block_indices[i] += 1;
160+
// look for the best free space block that can fit the file, only looking at the last of each size
161+
let mut best_free_space_block_idx = usize::MAX;
162+
for s in (right_block.length as usize)..spaces_block_indices_by_size.len() {
163+
if let Some(&found_idx) = spaces_block_indices_by_size[s].last() {
164+
if found_idx < right_block_idx && found_idx < best_free_space_block_idx {
165+
best_free_space_block_idx = found_idx;
159166
}
160-
break;
161-
} else if left_block.length == right_block.length {
162-
free_space_block_idx = Some(*space_idx);
163-
spaces_block_indices.remove(i);
164-
break;
165167
}
166168
}
167169

168-
if let Some(left_block_idx) = free_space_block_idx {
169-
let left_block = &blocks[left_block_idx];
170-
let (_, maybe_left_additional_space) = left_block.split(right_block.length);
170+
if best_free_space_block_idx == usize::MAX {
171+
right_block_idx -= 1;
172+
continue;
173+
}
171174

172-
if let Some(left_additional_space) = maybe_left_additional_space {
173-
blocks.insert(left_block_idx, right_block.clone());
174-
blocks[left_block_idx + 1] = left_additional_space;
175-
right_block_idx += 1;
176-
} else {
177-
blocks[left_block_idx] = right_block.clone();
175+
let left_block_idx = best_free_space_block_idx;
176+
let left_block = &blocks[left_block_idx];
177+
spaces_block_indices_by_size[left_block.length as usize].pop();
178+
179+
let (_, maybe_left_additional_space) = left_block.split(right_block.length);
180+
if let Some(left_additional_space) = maybe_left_additional_space {
181+
let new_idx = left_block_idx + 1;
182+
blocks.insert(left_block_idx, right_block.clone());
183+
184+
// shift all the indices that are greater than the left block index
185+
spaces_block_indices_by_size
186+
.iter_mut()
187+
.flat_map(|space_list| space_list.iter_mut())
188+
.filter(|idx| **idx > left_block_idx)
189+
.for_each(|idx| *idx += 1);
190+
191+
// add the new space to the list
192+
let space_list =
193+
&mut spaces_block_indices_by_size[left_additional_space.length as usize];
194+
let mut insert_idx = space_list.len();
195+
for i in (0..space_list.len()).rev() {
196+
if space_list[i] > new_idx {
197+
break;
198+
}
199+
insert_idx = i;
178200
}
201+
space_list.insert(insert_idx, new_idx);
179202

180-
blocks[right_block_idx].file_id = None;
181-
right_block_idx -= 1;
203+
blocks[new_idx] = left_additional_space;
204+
right_block_idx += 1;
205+
} else {
206+
blocks[left_block_idx] = right_block.clone();
182207
}
183208

209+
blocks[right_block_idx].file_id = None;
184210
right_block_idx -= 1;
185211
}
186212

@@ -214,4 +240,11 @@ mod tests {
214240
));
215241
assert_eq!(result, Some(2858));
216242
}
243+
244+
#[test]
245+
fn test_part_two_3() {
246+
let input = "55341271410101";
247+
let result = part_two(&input);
248+
assert_eq!(result, Some(638));
249+
}
217250
}

0 commit comments

Comments
 (0)