美文网首页
LintCode 200. 最长回文子串

LintCode 200. 最长回文子串

作者: CW不要无聊的风格 | 来源:发表于2020-05-26 10:18 被阅读0次

    题目描述

    给出一个字符串(假设长度最长为1000),求出它的最长回文子串,你可以假定只有一个满足条件的最长回文串。


    测试样例

    输入:"abcdzdcab"

    输出:"cdzdc"

    输入:"aba"

    输出:"aba"


    解题思路与方法

    1、暴力搜索

    i). 将输入字符串s逆序反转的到s1,比如abcde则变为edcba;

    ii). 依次遍历输入字符串s的每一个字符的位置,将其作为起始位i。每次固定i,然后从i开始依次遍历至字符串s的最后一个位置,将其作为终止位j。在这期间每遍历一个j便判断从i到j的子串是否出现在s1中,从而确定从i到j的子串是否回文;

    iii). 若s中从i到j的子串是回文,则比较这个回文子串与之前获得的最长回文子串的长度;若当前回文子串的长度大,则更新获得的最长回文子串长度,同时记录下最长回文子串的起止位置i、j;

    iv). 重复ii)和iii)直至将i遍历完s的所有字符位置

    2、动态规划

    i). 建立一个2维数组,用于记录从位置i到位置j是否是回文子串(O(n^2)的空间复杂度);

    ii). 依次遍历输入字符串s的每个位置,将其作为终止位right;然后从right开始向左边遍历每个位置,将其作为起始位置left,直至s的第一个字符位置;

    iii). 当left和right相邻或者两者之间的子串是回文,并且当前left和right位置的字符相等,那么更新2维数组,记录下从位置left到位置right是回文子串。同时,比较该回文子串与之前获得的最长回文子串的长度,若当前较大,则更新最长回文子串长度,同时记录下最长回文子串的起始位置分别为left和right;

    iv). 重复ii)和iii),直至right遍历完s的所有字符位置

    3、有点暴力的中线扩充

    i). 依次遍历输入字符串s的每个位置i,从i出发向左右两边扩充,获得left和right两个位置;

    ii). 同时,从i和i右边的一个位置j出发,分别向左和向右(i向左、j向右)扩充,获得left和right两个位置;

    iii). 在i)和ii)中,分别进入循环,对于每个left-right对,当它们都位于s中的有效位置且当前位于left和right的字符相等时,left和right就分别向左和向右移动,直至left和right有其一走到了s的有效位置之外或者left与right位置上的字符不相等,则跳出循环;

    iv). 跳出循环后,比较left和right之间的回文子串长度与之前获得的最长回文子串长度,若当前较大,则更新这个长度,同时记录下这个最长回文子串;

    v). 重复i)、ii)、iii)直至遍历完s中的所有位置


    代码

    1、暴力搜索

    class Solution:

        """

        @param s: input string

        @return: the longest palindromic substring

        """

        def longestPalindrome(self, s):

            # write your code here

            if not s:

                return ""

            if len(s) == 1:

                return s

            # 记录最长回文子串的长度

            longest_len = 0

            # 最长回文子串的起止,

            # 其中right是excluded,即[left, right)

            left = right = 0

            # 将字符串反转

            inverted_s = s[::-1]

            for i in range(len(s)):

                # 注意j要到len(s),这样才可能取到最后一个字符

                for j in range(i + 1, len(s) + 1):

                    if s[i:j] in inverted_s and len(s[i:j]) > longest_len:

                        left = i

                        right = j

                        longest_len = len(s[i:j])

            return s[left:right]

    2、动态规划

    class Solution:

        """

        @param s: input string

        @return: the longest palindromic substring

        """

        def longestPalindrome(self, s):

            # write your code here

            if not s:

                return ""

            if len(s) == 1:

                return s

            # 最长回文子串的头尾字符

            # 其中tail是included

            head = tail = 0

            # 记录最长回文子串的长度

            longest_len = 0

            # 记录从第i个字符到第j个字符是否是回文

            is_palindrome = [[False] * len(s) for _ in range(len(s))]

            for right in range(len(s)):

                for left in range(right, -1, -1):

                    if (right - left < 2 or is_palindrome[left + 1][right - 1]) \

                        and s[left] == s[right]:

                        is_palindrome[left][right] = True

                        cur_len = right - left + 1

                        if cur_len > longest_len:

                            head = left

                            tail = right

                            longest_len = cur_len

            return s[head:tail + 1]

    3、中线扩充

    class Solution:

        """

        @param s: input string

        @return: the longest palindromic substring

        """

        longest_palindrome = ''

        def longestPalindrome(self, s):

            # write your code here

            if not s:

                return ""

            if len(s) == 1:

                return s

            for start in range(len(s)):

                # 从start位置向两边扩展判断是否最长回文子串

                self.find_longest_palindrome(s, start, start)

                # 从start和start+1位置向两边扩展判断是否最长回文子串

                self.find_longest_palindrome(s, start, start + 1)

            return self.longest_palindrome

        def find_longest_palindrome(self, s, left, right):

            while left >= 0 and right < len(s) and s[left] == s[right]:

                left -= 1

                right += 1

            # 注意跳出循环后left是在回文子串的第一个字符的左边一个位置

            # right是在回文子串最后一个字符的右边一个位置

            if right - left - 1 > len(self.longest_palindrome):

                self.longest_palindrome = s[left + 1:right]

    相关文章

      网友评论

          本文标题:LintCode 200. 最长回文子串

          本文链接:https://www.haomeiwen.com/subject/encmahtx.html