214. Shortest Palindrome

来源:互联网 发布:应聘数据分析师面试题 编辑:程序博客网 时间:2024/05/20 11:21

题意: 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.

For example:

Given “aacecaaa”, return “aaacecaaa”.

Given “abcd”, return “dcbabcd”.

思路:这题一开始考虑错了,以为是在任意位置添加字幕,我当时想,我靠,这怎么做啊,然后才发现是在头部添加就可以了,首先讲一种利用Manacher’s Algorithm方法的解法,本来这个算法就是用来找最长回文子串的,而且其实这道题的目的就是找到最左侧回文子串的右边界,然后把右边剩下的部分反转之后加到左边来,比如对于”babad”,最左侧的“bab”就是最左侧回文子串,再把剩下的“ad”反过来加到开头构成“dababad”,再举个栗子:“ccababa”,最左侧的回文串是“cc”,把剩下的“ababa”反转之后加到开头即可,所以有了下面的代码:

class Solution(object):    def shortestPalindrome(self, s):        T = ['#']        for i in s:            T += ['#', i]        T += ['#', '$']        mx, id = 0, 0        P = [0] * len(T)        for i in xrange(1, len(T)-1):            if mx > i:                P[i] = min(P[2 * id - i], mx-i)            else:                P[i] = 1            while T[i + P[i]] == T[i - P[i]]:                P[i] += 1            if i+P[i] > mx:                mx = i + P[i]                id = i        max, max_idx = 0, 0        for i in xrange(1,len(T)-1):            if i-P[i] == 0:                max_len = P[i]-1        return s[len(s)-1:max_len-1:-1]+s

除了这种方法之外,还可以使用KMP来解,但是有个问题了,KMP如何找到一个字符串的最左回文的最右边界呢,比如对于一个串“aabba”,计算KMP的next数组为“-1,0,-1,-1,0”,这个完全没有头绪好吗,其实KMP算法求next的本质就是在整个串中标识出和初始位相同的串,所以如果把字串和它的反转字串合并呢?还是对于“aabba”,“aabba”+“abbaa”=“aabbaabbaa”,next数组为“-1,0,-1,-1,0,1,2,3,4,5”,如果开头几位和末尾几位相同,说明开头的几位就是回文了,而next数组的最后一位就表明了最左回文的最右边界,所以最左回文就是“aabbaa”,这里由于新构成的整个串比较独特,这个next[-1]=5超过了初始串“aabba”的长度,所以要i=next[i]=next[5]=1一下,所以新的边界就是next+1=2,这么说可能不好理解,这里还有一个更简单的方法,就是再构成新串的时候在中间加一个”#”,用来断开两个字符串,这样就不会出现next数组的值超过原始串长度的问题了,比如“aabba”+“#”+“abbaa”=“aabba#abbaa”,next数组为“-1,0,-1,-1,0,-1,0,-1,-1,0,1”,最右边界就是next[-1]+1=2,下面是”#”构造串的方法的代码:

class Solution(object):    def shortestPalindrome(self, s):        """        :type s: str        :rtype: str        """        def getPrefix(pattern):            prefix = [-1] * len(pattern)            j = -1            for i in xrange(1, len(pattern)):                while j > -1 and pattern[j+1] != pattern[i]:                    j = prefix[j]                if pattern[j+1] == pattern[i]:                    j += 1                prefix[i] = j            return prefix        if not s:            return s        A = s  +"#" + s[::-1]        prefix = getPrefix(A)        i = prefix[-1]        return s[i+1:][::-1] + s

当然不用“#”来构建串也是可以的:

class Solution(object):    def shortestPalindrome(self, s):        """        :type s: str        :rtype: str        """        def getPrefix(pattern):            prefix = [-1] * len(pattern)            j = -1            for i in xrange(1, len(pattern)):                while j > -1 and pattern[j+1] != pattern[i]:                    j = prefix[j]                if pattern[j+1] == pattern[i]:                    j += 1                prefix[i] = j            return prefix        if not s:            return s        A = s  + s[::-1]        prefix = getPrefix(A)        i = prefix[-1]        if i >= len(s):            i = prefix[i]        return s[i+1:][::-1] + s
0 0
原创粉丝点击