LeetCode第五题(Longest Palindromic Substring)

Longest Palindromic Substring

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

Example1:

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

Example2:

Input: "cbbd"
Output: "bb"

Python代码:
一开始的思路:

class Solution:
    def palindrome(self, s):
        """
        :type s: str
        :rtype: bool
        """
        i = 0
        j = len(s) - 1
        while i < j:
            if s[i] == s[j]:
                i += 1
                j -= 1
                continue
            else:
                return False
        return True
    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        llps = 0
        lps = []
        if len(s) == 0:
            return []
        if len(s) == 1:
            return s
        for i in range(0, len(s)-1):
            for j in range(len(s), i, -1):
                if self.palindrome(s[i:j]):
                    if len(s[i:j]) > llps:
                        lps = s[i:j]
                        llps = len(lps)
                else:
                    j -= 1
            i += 1
        return lps

这里写图片描述
结果当然就是无情的TLE。对上述代码进行简单的复杂度分析可知:题目要求最大长度为1000,设字符串长度为n,则palindrome()复杂度为O(n/2),对i跟j的嵌套循环复杂度为O(n^2),则总的复杂度为O(n^3),因此这样的暴力解法必然TLE。上网借鉴了一下别人的方法,终于可以AC了。


下面是真正可以AC的解法:

class Solution:
    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        if len(s) == 0:
            return []
        if len(s) == 1:
            return s
        if len(s) == 2:
            if s[0] == s[1]:
                return s
            return s[0]
        llps = 1
        lps = s[0]
        i = 0
        while i < len(s):
            j = i + 1
            while j < len(s):
                if s[i] == s[j]:    #处理有重复的字符串
                    j += 1
                else:
                    break
            k = 0       #重复字符串s[i:j]左右两边各有k长度的回文字符串
            while (i - k - 1) >= 0 and (j + k) < len(s):        #判定边界
                if s[i-k-1] == s[j+k]:
                    k += 1
                else:
                    break
            if (j - i + k*2) > llps:        #判断当前回文字符串的长度是否最长
                llps = j - i + k*2
                lps = s[i-k:j+k]
            if j + k == len(s) - 1:         #若抵达右边界则可以跳出循环了
                break
            i = j
        return lps

这里写图片描述
由上图可知,这是个非常trick的方法。
这里比较一下两个方法的核心思想:

  • 对于我自己的暴力解法:
    我是一步步从零开始构造回文字符串,不断遍历每种可能的字符串组合方式,并对其进行回文的判定,如果是回文字符串就比较其长度与之前的llps,如果比llps更长,那就把其加入到lps中,并更新llps,反之则继续遍历其他组合。这种解法不管如何都是妥妥的O(n^3)
  • 对于第二种解法:
    这种方法将初始回文字符串设为s[0],而后对每个回文字符串,同时往左右两边判断是否为回文,如果是就把回文字符串两边的下标再往左右移动,直到不是回文或者抵达边界为止,之后再判断当前下标间构成回文字符串的长度与llps,如果比llps更长,那就把其加入lps中,反之则将下标i移到j,继续以上步骤。
    该方法的巧妙之处在于将回文字符串内部连续重复的回文串的判断给简化了,最理想的情况就是之前没通过测试的”aaa…a”。在这种情况下,该算法的复杂度甚至为O(n)。当然最差情况下,也就是类似”abababa..aba”这种间断出现的字符串,该算法的复杂度为O(n^2),不过即便这样对于这个题目是可以接受的。

猜你喜欢

转载自blog.csdn.net/ax478/article/details/79810390
今日推荐