Skip to content

Commit 4d99c44

Browse files
committed
Faster simpler approach
1 parent 18c77ab commit 4d99c44

File tree

3 files changed

+30
-46
lines changed

3 files changed

+30
-46
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ pie
9595
| 3 | [Rucksack Reorganization](https://adventofcode.com/2022/day/3) | [Source](src/year2022/day03.rs) | 15 |
9696
| 4 | [Camp Cleanup](https://adventofcode.com/2022/day/4) | [Source](src/year2022/day04.rs) | 7 |
9797
| 5 | [Supply Stacks](https://adventofcode.com/2022/day/5) | [Source](src/year2022/day05.rs) | 14 |
98-
| 6 | [Tuning Trouble](https://adventofcode.com/2022/day/6) | [Source](src/year2022/day06.rs) | 6 |
98+
| 6 | [Tuning Trouble](https://adventofcode.com/2022/day/6) | [Source](src/year2022/day06.rs) | 3 |
9999
| 7 | [No Space Left On Device](https://adventofcode.com/2022/day/7) | [Source](src/year2022/day07.rs) | 10 |
100100
| 8 | [Treetop Tree House](https://adventofcode.com/2022/day/8) | [Source](src/year2022/day08.rs) | 55 |
101101
| 9 | [Rope Bridge](https://adventofcode.com/2022/day/9) | [Source](src/year2022/day09.rs) | 122 |

src/year2022/day06.rs

+27-43
Original file line numberDiff line numberDiff line change
@@ -5,64 +5,48 @@
55
//! as the window then we know that all characters are unique, as sets contain no duplicate elements.
66
//!
77
//! We'll use a faster approach that minimizes the work needed. Instead of creating a set for each
8-
//! window, we'll maintain a count of each character. As the window advances we add the next
9-
//! character to the count and remove the character the drops out of the window.
8+
//! window, we'll maintain the last position seen of each character. As we advance character by
9+
//! character we lookup the previous position. If this is within the packet size, then we advance
10+
//! the start of the packet to exclude that character. Once the packet has reached the desired
11+
//! size then we return the current index.
1012
//!
1113
//! [`windows`]: slice::windows
1214
//! [`HashSet`]: std::collections::HashSet
1315
14-
/// Convert the input string into a `vec` of `usize`, where "a" maps to 0 and "z" to 25.
15-
///
16-
/// Notes:
17-
/// * We need to [`trim`] to remove the trailing newline character
18-
/// * Advent of Code input is always ASCII characters, so casting to an `u8` slice is acceptable.
19-
///
20-
/// [`trim`]: str::trim
21-
pub fn parse(input: &str) -> Vec<usize> {
22-
input.trim().bytes().map(|b| (b - b'a') as usize).collect()
16+
/// Return the input directly.
17+
pub fn parse(input: &str) -> &str {
18+
input
2319
}
2420

2521
/// Find the first unique set of size 4
26-
pub fn part1(input: &[usize]) -> usize {
22+
pub fn part1(input: &str) -> usize {
2723
find(input, 4)
2824
}
2925

3026
/// Find the first unique set of size 14
31-
pub fn part2(input: &[usize]) -> usize {
27+
pub fn part2(input: &str) -> usize {
3228
find(input, 14)
3329
}
3430

35-
/// Efficient search algorithm.
36-
///
37-
/// The cardinality of the input is only 26 so a fixed size array can store the count of each
38-
/// character. We are interested in 2 transitions:
39-
/// * If the count for a character was 0 and is now 1, then this is the only character of this type
40-
/// in the window and we should increment the `different` counter by 1.
41-
/// * If the count for the character was 1 and is now 0, then the character is no longer present
42-
/// in the window, and we should decrement the `different` counter by 1.
43-
///
44-
/// All other transitions have no effect on the value of `different`. Once the `different` counter
45-
/// is the same as the window size then we return the 1-based index as our answer.
46-
fn find(input: &[usize], marker: usize) -> usize {
47-
let mut letters = [0; 26];
48-
let mut different = 0;
49-
50-
for i in 0..input.len() {
51-
let new = input[i];
52-
letters[new] += 1;
53-
if letters[new] == 1 {
54-
different += 1;
55-
}
56-
57-
if i >= marker {
58-
let old = input[i - marker];
59-
letters[old] -= 1;
60-
if letters[old] == 0 {
61-
different -= 1;
62-
}
31+
/// The cardinality of the input is only 26 so a fixed size array can store the last position
32+
/// of each character.
33+
fn find(input: &str, marker: usize) -> usize {
34+
let mut start = 0;
35+
let mut seen = [0; 26];
36+
37+
for (i, b) in input.bytes().enumerate() {
38+
// Use the character as an index into the array.
39+
let index = (b - b'a') as usize;
40+
let previous = seen[index];
41+
// Positions are 1-based.
42+
seen[index] = i + 1;
43+
44+
// There's a duplicate so advance the start of the window one character past it.
45+
if previous > start {
46+
start = previous;
6347
}
64-
65-
if different == marker {
48+
// We've reached the desired packet size with no duplicates so finish.
49+
if i + 1 - start == marker {
6650
return i + 1;
6751
}
6852
}

tests/year2022/day06_test.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ const EXAMPLE: &str = "mjqjpqmgbljsphdztnvjfqwrcgsmlb";
55
#[test]
66
fn part1_test() {
77
let input = parse(EXAMPLE);
8-
assert_eq!(part1(&input), 7);
8+
assert_eq!(part1(input), 7);
99
}
1010

1111
#[test]
1212
fn part2_test() {
1313
let input = parse(EXAMPLE);
14-
assert_eq!(part2(&input), 19);
14+
assert_eq!(part2(input), 19);
1515
}

0 commit comments

Comments
 (0)