Leetcode 214. 最短回文串
1.题目基本信息
1.1.题目描述
给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。
1.2.题目地址
https://leetcode.cn/problems/shortest-palindrome/description/
2.解题方法
2.1.解题思路
方法1:字符串哈希。将字符串转为整型哈希值。
方法2:KMP匹配算法。将s[::-1]作为查询串,s作为模式串,题目可以转换为求s[::-1]匹配的最长子串长度,也等价于求s模式串中指针最终指向的位置。
2.2.解题步骤
哈希算法方法步骤:
-
第一步,构建维护变量。left和right分别维护s的前缀的哈希值和前缀逆序的哈希值;multiNum维护当前哈希值整数的最高位;index维护满足s[:index+1]和s[:index+1][::-1]相等的最大的index
-
第二步,遍历字符串s,更新维护变量,并返回结果
KMP匹配算法方法步骤:
-
第一步,构建模式串的最长相同前后缀数组pmArr
-
1.1.设置需要的数据结构,一个存储pmArr元素的数组、不后退的从1开始的指针i、i-1处元素结尾的最长前后缀的长度
-
1.2.指针i勇往直前,直至模式串的结尾。在过程中,如果i处的值等于i-1处的最长相同前缀后的一个元素,则更新prefixLen和pmArr数组;如果不相等,且上一个最长相同前后缀的长度为0,说明是初始化情况或者递推到这里了,这种情况i处元素结尾的最长相同前后缀的长度为0,更新pmArr数组;如果不相等,且上一个最长相同前后缀的长度不为0,需要缩减上一个最长前后缀长度,将其缩减为上一个最长相同前后缀的最长相同前后缀,根据pmArr的前置的信息更新prefixLen。
-
-
第二步,根据pmArr数组进行子串匹配。让i和j指针分别指向被匹配串和模式串的元素,i指针不后退的遍历主串。过程中,如果i和j指向的元素值相同,i和j指针同时向前走一步;如果不相等,且j指针指向模式串的开头,则i指针前进一位;如果不相等,且j指针没有指向模式串的头部,则根据从pmArr中取出的j-1处元素结尾的最长前后缀的长度,并以此更新j的指针位置。
-
第三步,根据最终j指针的位置构建合法回文串
3.解题代码
哈希算法代码
class Solution:
def shortestPalindrome(self, s: str) -> str:
# 方法1:字符串哈希。将字符串转为整型哈希值
n = len(s)
mod = 10 ** 9 + 7
# 第一步,构建维护变量。left和right分别维护s的前缀的哈希值和前缀逆序的哈希值;multiNum维护当前哈希值整数的最高位;index维护满足s[:index+1]和s[:index+1][::-1]相等的最大的index
left, right = 0, 0
multiNum = 1
index = 0
# 第二步,遍历字符串s,更新维护变量,并返回结果
i = 0
while i < n:
c = s[i]
num = ord(c) - ord('a')
left = (left * 26 + num) % mod
right = (right + (multiNum * num)) % mod
multiNum *= 26
if left == right:
index = i
i += 1
return s[index + 1:][::-1] + s
KMP匹配算法代码
class Solution:
def shortestPalindrome(self, s: str) -> str:
# 方法2:KMP匹配算法。将s[::-1]作为查询串,s作为模式串,题目可以转换为求s[::-1]匹配的最长子串长度,也等价于求s模式串中指针最终指向的位置。
haystack = s[::-1]
needle = s
# 第一步,构建模式串的最长相同前后缀数组pmArr
# 1.1.设置需要的数据结构,一个存储pmArr元素的数组、不后退的从1开始的指针i、i-1处元素结尾的最长前后缀的长度
pmArr=[0] * len(needle)
prefixLen = 0
i = 1
# 1.2.指针i勇往直前,直至模式串的结尾。在过程中,如果i处的值等于i-1处的最长相同前缀后的一个元素,则更新prefixLen和pmArr数组;如果不相等,且上一个最长相同前后缀的长度为0,说明是初始化情况或者递推到这里了,这种情况i处元素结尾的最长相同前后缀的长度为0,更新pmArr数组;如果不相等,且上一个最长相同前后缀的长度不为0,需要缩减上一个最长前后缀长度,将其缩减为上一个最长相同前后缀的最长相同前后缀,根据pmArr的前置的信息更新prefixLen。
while i < len(needle):
if needle[i] == needle[prefixLen]:
prefixLen += 1
pmArr[i] = prefixLen
i += 1
else: # 不匹配
if prefixLen == 0:
i += 1
else:
# 关键点,理解+记忆
prefixLen = pmArr[prefixLen - 1]
# print("t1", pmArr)
# 第二步,根据pmArr数组进行子串匹配。让i和j指针分别指向被匹配串和模式串的元素,i指针不后退的遍历主串。过程中,如果i和j指向的元素值相同,i和j指针同时向前走一步;如果不相等,且j指针指向模式串的开头,则i指针前进一位;如果不相等,且j指针没有指向模式串的头部,则根据从pmArr中取出的j-1处元素结尾的最长前后缀的长度,并以此更新j的指针位置。
i = j = 0
while i < len(haystack):
if haystack[i] == needle[j]:
i += 1
j += 1
else: # 不匹配
if j == 0:
i += 1
else:
j = pmArr[j - 1]
# 匹配成功条件
# if len(needle) == j:
# return i - j
# 第三步,根据最终j指针的位置构建合法回文串
return s[j:][::-1] + s
4.执行结果


浙公网安备 33010602011771号