LeetCode-5. Longest Palindromic Substring(最长回文子串)

问题:给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

Example 1:

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

Example 2:

Input: "cbbd"
Output: "bb"

方法一:暴力解法

容易想到的方法往往耗时。思路是酱紫哒:一段字符串可能的最短回文是单个字符,可能的最长回文是它本身。那我们就设定一个窗口,长度从1到 len(s)。若有窗口长度w,依次以每个字符为起点,取长度为w的字符串,注意最后一个起点不可能是最后一个字符,否则窗口就填不满了。判断所取的字符串和它的反转字符串是否相同,若相同这个字符串就是回文。记录各次查找的最长回文。时间复杂度为O(n³),代码中虽然只有两重for循环,但第三次其实是b = a[::-1],这个反转过程是循环产生的。

#Python3
class Solution:
    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        l = 0;ans = "";a = b =""
        for w in range(1,len(s)+1):    #w为窗口长度
            for i in range(0,len(s)-w+1):    #每个窗口的起始位置,最后一个起点应是最后一个窗口的开头
                a = s[i:w+i];b = a[::-1]    #取这段窗口的字符串即其逆置字符串
                if a == b:    #如果这个窗口内的字符串和它的逆置字符串相等,则它是回文
                    if len(a) > l:    #如果这段回文比之前的回文长,那把这段回文作为最新答案
                        l = len(a)
                        ans = a
        return ans

方法二:动态规划

这个方法是对暴力解法的一个改进。暴力解法每次都要取字符串并进行判断,相当于把所有情况逐一列举出来。但动态规划对每次进行判断时,只要知道上一次是什么情况就可以了,也就是说只要我知道一个初始状态,我就可以从这个初始状态出发,根据一定的规则,依次推导出后面各个状态。首先定义 P(start,end),对于字符串s[start,end],如果它是回文,那么P(start,end)为True,否则为False。那怎么判断s[start,end]是否是回文?如果把该字符串两端去掉后,剩下的部分即s[start+1,end-1]是回文,那么只要s[start]==s[end],即新加上的两端相同,那么s[start,end]一定是回文。但是长度为1和2时,不能用上面的方法,长度为2时,假设我们求P(1,2),那么s[start+1,end-1]为s[2,1],实际情况不可能出现。对于p[start][end] = (w == 1 or w == 2 or p[start+1][end-1]) and (s[start] == s[end]),长度为1时,肯定是回文,长度为2时,因为要同时满足s[start] == s[end],所以长度为2也是回文。算法时间复杂度是O(n²)。

#Python
class Solution(object):
    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        maxL = 0;l = len(s);ans = ""    #maxL记录最大长度
        p = [[False for _ in range(l)]for _ in range(l)]    #生成二维数组
        for w in range(1,l+1):    #从1开始取窗口大小
            for start in range(0,l):    #设置起点
                end = start + w - 1
                if end >= l:    #如果终点超出所给字符总长,不合要求,结束本次循环
                    break
                p[start][end] = (w == 1 or w == 2 or p[start+1][end-1]) and (s[start] == s[end])    #判断条件
                if p[start][end] and w > maxL:    #如果是回文且比之前的回文都长
                    maxL = w;ans = s[start:end+1]
        return ans
//C++
class Solution {
public:
    string longestPalindrome(string s) {
        int len = s.length();
        if(len == 0) return "";
        bool p[len][len];memset(p, false, sizeof(p));    //memset()对p进行初始化
        int maxL = 0;
        string ans = "";
        for(int w = 1;w <= len;w++){
            for(int start = 0;start < len;start++){
                int end = start + w - 1;
                if(end >= len)
                    break;
                p[start][end] = (w == 1 || w == 2 || p[start+1][end-1]) && (s[start] == s[end]);
                if(p[start][end] && w > maxL){
                    maxL = w;
                    ans = s.substr(start,w);
                }
            }
        }
        return ans;
    }   
};

其实官方总共给了5中解法,但是我觉得还是要根据自己的情况从自己能掌握的开始。后面孰能生巧了,再去掌握那些更高级的算法。

猜你喜欢

转载自blog.csdn.net/theShepherd/article/details/85994602