Skip to content

Commit 740a053

Browse files
committed
perf(10/2015): use chunk_by, calculate on bytes to avoid String allocations
1 parent a4bf8e9 commit 740a053

File tree

2 files changed

+29
-43
lines changed

2 files changed

+29
-43
lines changed

readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@
9696
| [Day 7: Some Assembly Required](src/solutions/year2015/day07.rs) | ⭐⭐ | 0.308 | 0.293 |
9797
| [Day 8: Matchsticks](src/solutions/year2015/day08.rs) | ⭐⭐ | 0.052 | 0.129 |
9898
| [Day 9: All in a Single Night](src/solutions/year2015/day09.rs) | ⭐⭐ | 34.320 | 34.850 |
99-
| [Day 10: Elves Look, Elves Say](src/solutions/year2015/day10.rs) | ⭐⭐ | 18.273 | 148.464 |
99+
| [Day 10: Elves Look, Elves Say](src/solutions/year2015/day10.rs) | ⭐⭐ | 2.099 | 32.258 |
100100

101101
# TODO
102102

src/solutions/year2015/day10.rs

Lines changed: 28 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,67 +4,53 @@ pub struct Day10;
44

55
impl Solution for Day10 {
66
fn part_one(&self, input: &str) -> String {
7-
self.look_and_say_for_string(input, 40).len().to_string()
7+
look_and_say_n_times(input.trim(), 40).len().to_string()
88
}
99

1010
fn part_two(&self, input: &str) -> String {
11-
self.look_and_say_for_string(input, 50).len().to_string()
11+
look_and_say_n_times(input.trim(), 50).len().to_string()
1212
}
1313
}
1414

15-
impl Day10 {
16-
fn look_and_say_for_string(&self, input: &str, times: usize) -> String {
17-
let mut numbers: Vec<u8> = input
18-
.trim()
19-
.chars()
20-
.map(|c| c.to_string().parse::<u8>().unwrap())
21-
.collect();
15+
fn look_and_say_n_times(input: &str, iterations: usize) -> String {
16+
let mut numbers: Vec<u8> = input
17+
.bytes()
18+
.map(|b| b - b'0') // 53 (ASCII for 5) - 48 (ASCII for 0) = 5 ✓
19+
.collect();
2220

23-
for _ in 0..times {
24-
numbers = self.look_and_say(&numbers);
25-
}
26-
27-
numbers.iter().map(|u| u.to_string()).collect::<String>()
21+
for _ in 0..iterations {
22+
numbers = look_and_say(&numbers);
2823
}
2924

30-
fn look_and_say(&self, numbers: &[u8]) -> Vec<u8> {
31-
let mut current = numbers[0];
32-
let mut count = 1u8;
33-
let mut index = 1;
34-
let mut vec: Vec<u8> = Vec::new();
35-
36-
while let Some(value) = numbers.get(index) {
37-
if *value == current {
38-
count += 1;
39-
index += 1;
40-
continue;
41-
} else {
42-
vec.push(count);
43-
vec.push(current);
25+
numbers.iter().map(|&n| (n + b'0') as char).collect()
26+
}
4427

45-
count = 1;
46-
index += 1;
47-
current = *value;
48-
}
49-
}
28+
fn look_and_say(numbers: &[u8]) -> Vec<u8> {
29+
if numbers.is_empty() {
30+
return Vec::new();
31+
}
5032

51-
vec.push(count);
52-
vec.push(current);
33+
let mut result = Vec::with_capacity(numbers.len() * 3 / 2);
34+
let chunks = numbers.chunk_by(|a, b| a == b);
5335

54-
vec
36+
for chunk in chunks {
37+
result.push(chunk.len() as u8);
38+
result.push(chunk[0]);
5539
}
40+
41+
result
5642
}
5743

5844
#[cfg(test)]
5945
mod tests {
6046
use super::*;
6147

6248
#[test]
63-
fn look_and_say() {
64-
assert_eq!("11", Day10.look_and_say_for_string("1", 1));
65-
assert_eq!("21", Day10.look_and_say_for_string("11", 1));
66-
assert_eq!("1211", Day10.look_and_say_for_string("21", 1));
67-
assert_eq!("111221", Day10.look_and_say_for_string("1211", 1));
68-
assert_eq!("312211", Day10.look_and_say_for_string("111221", 1));
49+
fn test_look_and_say() {
50+
assert_eq!("11", look_and_say_n_times("1", 1));
51+
assert_eq!("21", look_and_say_n_times("11", 1));
52+
assert_eq!("1211", look_and_say_n_times("21", 1));
53+
assert_eq!("111221", look_and_say_n_times("1211", 1));
54+
assert_eq!("312211", look_and_say_n_times("111221", 1));
6955
}
7056
}

0 commit comments

Comments
 (0)