【算法】5. Longest Palindromic Substring

题目:

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of sis 1000.

举例:

Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.
Input: "cbbd"
Output: "bb"

      本题是最长回文串问题。其几种解法非常经典,之前对于马拉车算法不太熟悉,在这里也一并回顾一下。

一、暴力解法

      遍历所有字符串,分别判断其是否为回文串。在遍历过程中,记录最长的字符串。

1.  如下字符串"abcdede", 首先选取字符串,共有  C^2_8  种,若长度为 n,为C^2_n =\frac{n(n-1)}{2}, 时间复杂度O(n^2).

                                      | a | b | c | d | e | d | e |

2. 第二步,分别判断是否为回文串,头尾各一指针,判断是否相等。

因而 总的时间复杂度为 O(n^3),时间复杂度太高,不能通过。

class Solution(object):
    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        n = len(s)
        maxval = ""
        if len(s)<=1:
            return s
        def isPalindrome(s):
            n = len(s)
            i = 0 
            j = n-1
            while(i<=j):
                if s[i]==s[j]:
                    i += 1
                    j -= 1
                else:
                    break
            if i<j:
                return False
            else:
                return True
        i = 0
        while i<n:
            j = i+1
            while j <n+1:
                if isPalindrome(s[i:j]):
                    if len(maxval)<j-i:
                        maxval = s[i:j]
                j += 1
            i += 1
        return maxval

二、 中间指针法

不从两头判断,从中间往外扩散。整体时间复杂度为O(n^2)。

1. 第一层循环,遍历所有元素;

2. 第二层循环,往外扩散,记录最长回文串。

这里值得注意的是,需要对奇偶情况做一个区分:例如 “aba" 和 ”abba"均为回文串,但是遍历方法有区别。

class Solution(object):
    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        n = len(s)
        maxlength = 0
        val = (0,0)
        def count_length(s,i,j):
            while i>= 0 and j<n and s[i] == s[j]:
                i -= 1
                j += 1
            return j-i-1,(i,j)
                
            
        for i in range(n):
            single,pair_s = count_length(s,i,i)
            double,pair_d = count_length(s,i-1,i)
            if single > double and single >maxlength:
                maxlength = single
                val = pair_s
            if double > single and double > maxlength:
                maxlength = double
                val = pair_d
        return s[val[0]+1:val[1]]

三、马拉车算法

       马拉车算法是基于二的一个改进,将时间复杂度进一步提高到O(n)。

       主要是两个方面,首先简化奇偶判断,通过插入“#”,保证了长度为奇数(2n+1)。

举例: bob    -->    #b#o#b#

           noon    -->    #n#o#o#n#

       其次,主要在减少遍历上做了工作,增加了一个数组,记录以其为中心时的最大字符串长度,

例如:  # a # b # c # b # d

          [  1 2 1 2 1 4 1 2 1 1 ]

       如果按照常规,需要对每个元素进行遍历判断最长回文串,但根据该算法的规则可以减少一些判断,从而降低时间复杂度:

       可见下图,以 id 为中心的最长回文串范围为 C = [mx的对称点,mx],如果点 i 在以 id 为中心的最长回文串范围内,其关于id 的对称点为 j(j=2*id-i),根据回文串的对称特性,i 在范围 C 内与 j 对称,以 i 为中心的回文串的长度和 j 相同,为 Lj 。因而如果 j 的回文串范围在 mx 以内,i 的长度直接为 j 的长度 Lj。如果超过该范围,则超过部分需要继续判断。这一部分是核心,剩余就是如果 i > mx,需要按之前方式判断。

总结:      

if mx > i, 则 p[i] = min( p[2 * id - i] , mx - i ),这里又分为两个部分,一个是在范围内,一个是超过范围,分开讨论;

else,p[i] = 1,继续判断

执行时间108ms,相比而言,速度较快。

class Solution(object):
    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        new_s  = list('#' + '#'.join(s) + '#')
        
        mx = 0
        val = (0,0)
        ids = 0
        matrix = [0 for _ in range(len(new_s))]
        def count_length(s,i,j):
            cnt = 0 
            while i>=0 and j<len(s) and s[i] == s[j]:
                i -= 1
                j += 1
                cnt += 1
            return cnt,(i+1,j)
        
        for i in range(len(new_s)):
            if i < mx:
                j = 2 * ids - i
                if matrix[j] < mx - i:
                    matrix[i] = matrix[j]
                else:
                    res,pair = count_length(new_s,2*i-mx,mx)
                    matrix[i] = mx -i + res
                    ids = i
                    if (val[1] - val[0]+1)/2 < matrix[i]:
                        val = pair
                        mx = i + matrix[i] - 1
            else:
                l,pair = count_length(new_s,i,i)
                mx = i + l - 1
                ids = i
                matrix[i] = l
                if (val[1] - val[0]+1)/2 < l:
                    val = pair
        return s[val[0]/2:val[1]/2]

            
                 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章