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.执行结果

posted @ 2025-07-06 15:44  Geek0070  阅读(5)  评论(0)    收藏  举报