【算法】leetcode5 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]

            
                 

 

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