Manacher’s Algorithm 是一种高效查询最长回文串的算法,我在 lintcode 题目中用于统计输入的字符串拥有多少个回文子串。
原文共 4 篇,part1 & part2 主要介绍原理,part3 & part4 为具体实现。
推荐中文参考:https://www.felix021.com/blog/read.php?2040
我把求解的条件整理如下。
3 Answers and 4 Different Cases
currentLeftPosition = 2 * centerPosition – currentRightPosition
-
ANS 1: L[currentRightPosition] = L[currentLeftPosition]
-
CASE 1: L[currentLeftPosition] < centerRightPosition – currentRightPosition
- i-left palindrome is NOT prefix of the center palindrome
- i-left palindrome is completely contained in the center palindrome
-
CASE 2: L[currentLeftPosition] == centerRightPosition – currentRightPosition
-
i-left palindrome is prefix of the center palindrome
-
center palindrome is suffix of the entire input string
(centerRightPosition = 2*N where N is input string length N)
-
-
-
ANS 2: L[currentRightPosition] >= L[currentLeftPosition]
-
CASE 3: L[currentLeftPosition] == centerRightPosition – currentRightPosition
-
i-left palindrome is prefix of center palindrome
(i-left palindrome is completely contained in center palindrome)
-
center palindrome is NOT suffix of input string
(centerRightPosition < 2 * N where N is input string length N)
-
-
-
ANS 3: L[currentRightPosition] >= centerRightPosition – currentRightPosition
- CASE 4: L[currentLeftPosition] > centerRightPosition – currentRightPosition
- i-left palindrome is NOT completely contained in center palindrome
- CASE 4: L[currentLeftPosition] > centerRightPosition – currentRightPosition
What Would Be Next CenterPosition?
We change centerPosition to currentRightPosition if palindrome centered at currentRightPosition expands beyond centerRightPosition.
Solution
请求一个数组 L ,长度为 2N + 1 ,N 个空间给输入字符串,N + 1 个空间用于隔断 N 个字符。
L[i] 保存当前字符/隔断对应的回文串长度,如果当前字符/隔断没有回文串,字符的 L[i] 为 1 (字符本身也属于回文串),隔断的 L[i] 为 0 。
初始化 L [1] 为 1 ,利用已计算出的长度,减少甚至不去计算后面对称的子串长度。
def findLongestPalindromicString(self, str):
N = len(str)
if N == 0:
return
N = 2 * N + 1 # Position (insert separator)
L = [0] * N
# the first seperator has no palindrome length
# the first character has one length in the start
L[1] = 1
C = 1 # centerPosition
R = 2 # centerRightPosition
# i is currentRightPosition
for i in range(2, N):
iMirror = 2 * C - i
diff = R - i
if L[iMirror] <= diff:
L[i] = L[iMirror]
else:
L[i] = diff
try:
# character will do compare, seperator just add ONE directly
while ((i + L[i]) < N and (i - L[i]) > 0) and \
(((i + L[i] + 1) % 2 == 0) or
(str[(i + L[i] + 1) // 2] == str[(i - L[i] - 1) // 2])):
L[i] += 1
except:
pass
if i + L[i] > R:
C, R = i, i + L[i]
return sum([(l + 1) // 2 for l in L])
Other Solutions
def countPalindromicSubstrings(self, str):
# write your code here
length = len(str)
count = 0
for l in range(2 * length - 1):
left = right = l // 2
if l % 2 != 0:
right += 1
while left >= 0 and right < length and str[left] == str[right]:
count += 1
left -= 1
right += 1
return count
def dp(self, str):
l = len(str)
t = [[False for col in range(l)] for row in range(l)]
for i in range(l):
t[i][i] = True
if i + 1 < l and str[i] == str[i + 1]:
t[i][i + 1] = True
sub_l = 3
while sub_l <= l:
i = 0
while i < (l - sub_l + 1):
j = i + sub_l - 1
if t[i + 1][j - 1] and str[i] == str[j]:
t[i][j] = True
i += 1
sub_l += 1
count = 0
for i in range(l):
for j in range(i, l):
if t[i][j] == True:
count += 1
return count
网友评论