@@ -10,15 +10,17 @@ impl Solution for Day14 {
1010 let input = input. trim ( ) ;
1111 let hash_generator = HashGenerator :: new ( input. to_string ( ) ) ;
1212 let mut count = 0 ;
13+ let three_tuples = Md5Tuple :: new ( 3 ) ;
14+ let five_tuples = Md5Tuple :: new ( 5 ) ;
1315
1416 for i in 0usize .. {
1517 let three_hash = hash_generator. get ( i) ;
1618
17- if let Some ( first_three_tuple) = self . find_first_tuple ( & three_hash, 3 ) {
19+ if let Some ( first_three_tuple) = three_tuples . find_first_tuple ( three_hash) {
1820 for j in i + 1 ..=i + 1000 {
1921 let five_hash = hash_generator. get ( j) ;
2022
21- if self . contains_tuple ( & five_hash, first_three_tuple, 5 ) {
23+ if five_tuples . contains_tuple ( & five_hash, first_three_tuple) {
2224 count += 1 ;
2325
2426 if count == 64 {
@@ -67,36 +69,59 @@ impl HashGenerator {
6769 }
6870}
6971
70- impl Day14 {
71- fn find_first_tuple ( & self , digest : & str , length : usize ) -> Option < u8 > {
72- let mut iter = digest . bytes ( ) ;
73- let mut current = iter . next ( ) . unwrap ( ) ;
72+ struct Md5Tuple {
73+ length : usize ,
74+ first_tuple_cache : RefCell < HashMap < String , Option < u8 > > > ,
75+ }
7476
75- let mut count = 1 ;
77+ impl Md5Tuple {
78+ fn new ( length : usize ) -> Md5Tuple {
79+ Self {
80+ length,
81+ first_tuple_cache : RefCell :: new ( HashMap :: new ( ) ) ,
82+ }
83+ }
7684
77- for c in iter {
78- if c == current {
79- count += 1 ;
85+ fn find_first_tuple ( & self , digest : String ) -> Option < u8 > {
86+ if let Some ( cached) = self . first_tuple_cache . borrow ( ) . get ( & digest. clone ( ) ) {
87+ return * cached;
88+ }
89+
90+ let result = {
91+ let str = digest. as_str ( ) ;
92+ let mut iter = str. bytes ( ) ;
93+ let mut current = iter. next ( ) . unwrap ( ) ;
8094
81- if count == length {
82- return Some ( c) ;
95+ let mut count = 1 ;
96+
97+ for c in iter {
98+ if c == current {
99+ count += 1 ;
100+
101+ if count == self . length {
102+ return Some ( c) ;
103+ }
104+ } else {
105+ current = c;
106+ count = 1 ;
83107 }
84- } else {
85- current = c;
86- count = 1 ;
87108 }
88- }
89109
90- None
110+ None
111+ } ;
112+
113+ self . first_tuple_cache . borrow_mut ( ) . insert ( digest, result) ;
114+
115+ result
91116 }
92117
93- fn contains_tuple ( & self , digest : & str , char_byte : u8 , target_len : usize ) -> bool {
118+ fn contains_tuple ( & self , digest : & str , char_byte : u8 ) -> bool {
94119 let mut count = 0 ;
95120
96121 for & byte in digest. as_bytes ( ) {
97122 if byte == char_byte {
98123 count += 1 ;
99- if count == target_len {
124+ if count == self . length {
100125 return true ;
101126 }
102127 } else {
@@ -121,8 +146,23 @@ mod tests {
121146
122147 #[ test]
123148 fn find_all_tuples ( ) {
124- assert_eq ! ( b'8' , Day14 . find_first_tuple( "cc38887a5" , 3 ) . unwrap( ) ) ;
125- assert_eq ! ( b'8' , Day14 . find_first_tuple( "cc38887aaa5" , 3 ) . unwrap( ) ) ;
126- assert_eq ! ( b'a' , Day14 . find_first_tuple( "aaa" , 3 ) . unwrap( ) ) ;
149+ assert_eq ! (
150+ b'8' ,
151+ Md5Tuple :: new( 3 )
152+ . find_first_tuple( "cc38887a5" . to_string( ) )
153+ . unwrap( )
154+ ) ;
155+ assert_eq ! (
156+ b'8' ,
157+ Md5Tuple :: new( 3 )
158+ . find_first_tuple( "cc38887aaa5" . to_string( ) )
159+ . unwrap( )
160+ ) ;
161+ assert_eq ! (
162+ b'a' ,
163+ Md5Tuple :: new( 3 )
164+ . find_first_tuple( "aaa" . to_string( ) )
165+ . unwrap( )
166+ ) ;
127167 }
128168}
0 commit comments