1
- # calculate palindromic length from center with incrementing difference
2
- def palindromic_length (center , diff , string ):
3
- if (
4
- center - diff == - 1
5
- or center + diff == len (string )
6
- or string [center - diff ] != string [center + diff ]
7
- ):
8
- return 0
9
- return 1 + palindromic_length (center , diff + 1 , string )
10
-
11
-
12
1
def palindromic_string (input_string ):
13
2
"""
14
- Manacher’s algorithm which finds Longest Palindromic Substring in linear time.
3
+ >>> palindromic_string('abbbaba')
4
+ 'abbba'
5
+ >>> palindromic_string('ababa')
6
+ 'ababa'
7
+
8
+ Manacher’s algorithm which finds Longest palindromic Substring in linear time.
15
9
16
10
1. first this convert input_string("xyx") into new_string("x|y|x") where odd
17
11
positions are actual input characters.
18
- 2. for each character in new_string it find corresponding length and store,
19
- a. max_length
20
- b. max_length's center
21
- 3. return output_string from center - max_length to center + max_length and remove
22
- all "|"
12
+ 2. for each character in new_string it find corresponding length and store the length
13
+ and l,r to store previously calculated info.(please look the explanation for details)
14
+
15
+ 3. return corresponding output_string by removing all "|"
23
16
"""
24
17
max_length = 0
25
18
@@ -33,25 +26,78 @@ def palindromic_string(input_string):
33
26
# append last character
34
27
new_input_string += input_string [- 1 ]
35
28
29
+ # we will store the starting and ending of previous furthest ending palindromic substring
30
+ l , r = 0 , 0
31
+
32
+ # length[i] shows the length of palindromic substring with center i
33
+ length = [1 for i in range (len (new_input_string ))]
34
+
36
35
# for each character in new_string find corresponding palindromic string
37
36
for i in range (len (new_input_string )):
37
+ k = 1 if i > r else min (length [l + r - i ] // 2 , r - i + 1 )
38
+ while (
39
+ i - k >= 0
40
+ and i + k < len (new_input_string )
41
+ and new_input_string [k + i ] == new_input_string [i - k ]
42
+ ):
43
+ k += 1
44
+
45
+ length [i ] = 2 * k - 1
38
46
39
- # get palindromic length from i-th position
40
- length = palindromic_length (i , 1 , new_input_string )
47
+ # does this string is ending after the previously explored end (that is r) ?
48
+ # if yes the update the new r to the last index of this
49
+ if i + k - 1 > r :
50
+ l = i - k + 1
51
+ r = i + k - 1
41
52
42
53
# update max_length and start position
43
- if max_length < length :
44
- max_length = length
54
+ if max_length < length [ i ] :
55
+ max_length = length [ i ]
45
56
start = i
46
57
47
58
# create that string
48
- for i in new_input_string [start - max_length : start + max_length + 1 ]:
59
+ s = new_input_string [start - max_length // 2 : start + max_length // 2 + 1 ]
60
+ for i in s :
49
61
if i != "|" :
50
62
output_string += i
51
63
52
64
return output_string
53
65
54
66
55
67
if __name__ == "__main__" :
56
- n = input ()
57
- print (palindromic_string (n ))
68
+ import doctest
69
+
70
+ doctest .testmod ()
71
+
72
+ """
73
+ ...a0...a1...a2.....a3......a4...a5...a6....
74
+
75
+ consider the string for which we are calculating the longest palindromic substring is shown above where ...
76
+ are some characters in between and right now we are calculating the length of palindromic substring with
77
+ center at a5 with following conditions :
78
+ i) we have stored the length of palindromic substring which has center at a3 (starts at l ends at r) and it
79
+ is the furthest ending till now, and it has ending after a6
80
+ ii) a2 and a4 are equally distant from a3 so char(a2) == char(a4)
81
+ iii) a0 and a6 are equally distant from a3 so char(a0) == char(a6)
82
+ iv) a1 is corresponding equal character of a5 in palindrome with center a3 (remember that in below derivation of a4==a6)
83
+
84
+ now for a5 we will calculate the length of palindromic substring with center as a5 but can we use previously
85
+ calculated information in some way?
86
+ Yes, look the above string we know that a5 is inside the palindrome with center a3 and previously we have
87
+ have calculated that
88
+ a0==a2 (palindrome of center a1)
89
+ a2==a4 (palindrome of center a3)
90
+ a0==a6 (palindrome of center a3)
91
+ so a4==a6
92
+
93
+ so we can say that palindrome at center a5 is at least as long as palindrome at center a1
94
+ but this only holds if a0 and a6 are inside the limits of palindrome centered at a3 so finally ..
95
+
96
+ len_of_palindrome__at(a5) = min(len_of_palindrome_at(a1), r-a5)
97
+ where a3 lies from l to r and we have to keep updating that
98
+
99
+ and if the a5 lies outside of l,r boundary we calculate length of palindrome with bruteforce and update
100
+ l,r.
101
+
102
+ it gives the linear time complexity just like z-function
103
+ """
0 commit comments