@@ -4,74 +4,56 @@ pub fn manacher(s: String) -> String {
44 return s;
55 }
66
7- // MEMO: We need to detect odd palindrome as well,
8- // therefore, inserting dummy string so that
9- // we can find a pair with dummy center character.
7+ // 1. Preprocessing: insert separators
108 let mut chars: Vec < char > = Vec :: with_capacity ( s. len ( ) * 2 + 1 ) ;
119 for c in s. chars ( ) {
1210 chars. push ( '#' ) ;
1311 chars. push ( c) ;
1412 }
1513 chars. push ( '#' ) ;
14+ let n = chars. len ( ) ;
1615
17- // List: storing the length of palindrome at each index of string
18- let mut length_of_palindrome = vec ! [ 1usize ; chars. len( ) ] ;
19- // Integer: Current checking palindrome's center index
20- let mut current_center: usize = 0 ;
21- // Integer: Right edge index existing the radius away from current center
22- let mut right_from_current_center: usize = 0 ;
16+ // 2. p[i] represents the radius—how far it can expand symmetrically from the center in both directions.
17+ let mut p = vec ! [ 0usize ; n] ;
18+ let mut center = 0 ;
19+ let mut right = 0 ;
2320
24- for i in 0 ..chars. len ( ) {
25- // 1: Check if we are looking at right side of palindrome.
26- if right_from_current_center > i && i > current_center {
27- // 1-1: If so copy from the left side of palindrome.
28- // If the value + index exceeds the right edge index, we should cut and check palindrome later #3.
29- length_of_palindrome[ i] = std:: cmp:: min (
30- right_from_current_center - i,
31- length_of_palindrome[ 2 * current_center - i] ,
32- ) ;
33- // 1-2: Move the checking palindrome to new index if it exceeds the right edge.
34- if length_of_palindrome[ i] + i >= right_from_current_center {
35- current_center = i;
36- right_from_current_center = length_of_palindrome[ i] + i;
37- // 1-3: If radius exceeds the end of list, it means checking is over.
38- // You will never get the larger value because the string will get only shorter.
39- if right_from_current_center >= chars. len ( ) - 1 {
40- break ;
41- }
21+ for i in 0 ..n {
22+ // Mirror position
23+ let mirror = 2 * center as isize - i as isize ;
24+ // Inherit the value from the mirror
25+ if i < right {
26+ if mirror >= 0 {
27+ p[ i] = p[ mirror as usize ] . min ( right - i) ;
4228 } else {
43- // 1-4: If the checking index doesn't exceeds the right edge,
44- // it means the length is just as same as the left side.
45- // You don't need to check anymore.
46- continue ;
29+ p[ i] = 0 ;
4730 }
4831 }
4932
50- // Integer: Current radius from checking index
51- // If it's copied from left side and more than 1,
52- // it means it's ensured so you don't need to check inside radius.
53- let mut radius: usize = ( length_of_palindrome[ i] - 1 ) / 2 ;
54- radius += 1 ;
55- // 2: Checking palindrome.
56- // Need to care about overflow usize.
57- while i >= radius && i + radius <= chars. len ( ) - 1 && chars[ i - radius] == chars[ i + radius]
58- {
59- length_of_palindrome[ i] += 2 ;
60- radius += 1 ;
33+ // Expand
34+ while i + p[ i] + 1 < n && i > p[ i] && chars[ i + p[ i] + 1 ] == chars[ i - p[ i] - 1 ] {
35+ p[ i] += 1 ;
36+ }
37+
38+ // Update the center and the right boundary
39+ if i + p[ i] > right {
40+ center = i;
41+ right = i + p[ i] ;
6142 }
6243 }
6344
64- // 3: Find the maximum length and generate answer.
65- let center_of_max = length_of_palindrome
66- . iter ( )
67- . enumerate ( )
68- . max_by_key ( |( _, & value) | value)
69- . map ( |( idx, _) | idx)
70- . unwrap ( ) ;
71- let radius_of_max = ( length_of_palindrome[ center_of_max] - 1 ) / 2 ;
72- let answer = & chars[ ( center_of_max - radius_of_max) ..=( center_of_max + radius_of_max) ]
45+ // 3. Find the maximum
46+
47+ let ( center_of_max, & radius_of_max) = p. iter ( ) . enumerate ( ) . max_by_key ( |& ( _, & x) | x) . unwrap ( ) ;
48+
49+ // 4. Construct the answer
50+ let start = center_of_max - radius_of_max;
51+ let end = center_of_max + radius_of_max;
52+ let answer: String = chars[ start..=end]
7353 . iter ( )
74- . collect :: < String > ( ) ;
54+ . filter ( |& & c| c != '#' )
55+ . cloned ( )
56+ . collect ( ) ;
7557 answer. replace ( '#' , "" )
7658}
7759
0 commit comments