【Leetcode】214. Shortest Palindrome 最短回文串

Given a string s, you are allowed to convert it to a palindrome by adding characters in front of it. Find and return the shortest palindrome you can find by performing this transformation.

Example 1:

Input: “aacecaaa”
Output: “aaacecaaa”

Example 2:

Input: “abcd”
Output: “dcbabcd”

解法

这题的重点其实是要找到以s[0]开头的最长回文子串的长度

解法一:马拉车

详细解释在516. Longest Palindromic Subsequence
我自己是用这个算法解的,这个算法本来是用来遍历一遍所有可能的中点,然后对每个中点计算最长回文子串的,我们只需要遍历一半的中点,中点越靠右半径越大

class Solution(object):
    def shortestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        n = len(s)
        l = 2*n-1
        p = [0]*l
        rm = 0
        ans = 1
        
        def equal(i,r):
            if (i+r)%2!=0:
                return True
            return s[(i+r)//2]==s[(i-r)//2]
        
        for i in xrange(1,n):
            if i<=rm+p[rm]:
                p[i] = min(rm+p[rm]-i,p[2*rm-i])
            while i-p[i]>0 and i+p[i]<l-1 and equal(i,p[i]+1):
                    p[i] += 1
            if i+p[i]>rm+p[rm]:
                rm = i
            if i-p[i]==0:
                ans = (i+p[i])//2+1
        return s[ans:][::-1]+s

解法二:KMP

KMP的核心是next[i]=j表示s[0..j-1]=s[i-j..i-1]
一开始我也想用KMP,但是只在原字符串用KMP有个问题,就是i不可能等于j,所以不会遍历到回文子串。
我们可以新建一个大的字符串:ss=s+"#"+s[::-1],它的长度为2*n+1"#"的下标为n
这样,对于ss[0..j-1]=ss[i-j,i-1]。由于中间被#隔开了,所以一定有j-1i-j>n。那么,当i=2n+1(也就是ss[i-1]对应s[0])时,next[i]就是以s[0]开头的最长回文子串的长度

class Solution(object):
    def shortestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        n = len(s)
        ss = s+'#'+s[::-1]
        f = [-1]*(2*n+2)
        for i in xrange(1,2*n+2):
            j = f[i-1]
            while j>=0 and ss[j]!=ss[i-1]:
                j = f[j]
            f[i] = j+1 if j>=0 else 0
        return s[f[i]:][::-1]+s

你可能感兴趣的:(Leetcode)