LeetCode 5: Longest Palindromic Substring

Description:

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

Example 1:

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

Example 2:

Input: "cbbd"
Output: "bb"

描述:

给定字符串s,查找s的最长回文子串。

假设字符串s的最大长度为1000.

示例1:

输入: “babad”
输出: "bab"
注意:“aba”也是有效的答案

示例2:

输入:“cbbd”
输出: “bb”

 

方法一:暴力破解

首先,明确回文的概念。“回文串”是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串。

遍历字符串s的每一个子串,并判断该子字符串是否为回文。

 

class Solution {
public:
    string longestPalindrome(string s) {
        int len = s.length();
        string str;
        int maxLen = 0;
        if(len == 0) return s;
        for(int i = 0; i < len; i++) {
            for(int j = i + 1; j <= len; j++) {
                int len = palindromeLen(s, i, j);
                if(len >= maxLen) {
                    maxLen = len;
                    str = s.substr(i, j - i);
                }
            }
        }
        return str;
    }
    
    int palindromeLen(string str, int start, int end) {
        int s = start;
        int e = end - 1;
        while(s <= e) {
            if(str[s++] != str[e--])
                return 0;
        }
        return end - start;
    }
};

  该方法的时间复杂度为O(n3),空间复杂度为O(n)。运行时间为1796ms。

 

方法2:动态规划

首先,我们考虑如何减少重复比较的次数。以“ababa”为例,如果我们已经知道“bab”为回文,那么“ababa”也是回文,因为“bab”首端和末端的字符相等,均为字符‘a’。

显而易见地,

P(i,j) = true, 如果Si,...,Sj为回文串,反之,P(i,j) = false

因此,P(i,j) = (P(i+1, j-1) and Si == Sj)。

并且,P(i,i) = true, 当Si == Si+1时P(i, i+1) = true。

class Solution {
public:
    string longestPalindrome(string s) {
        int len = s.length();
        if(len == 0 || len == 1)
            return s;
        
        bool p[len][len];
        for(int i = 0; i < len; i++) {
            for(int j = 0; j < len; j++) {
                p[i][j] = false;
            }
        }
        
        int maxLen = 0;
        string ans;
        for(int l = 0; l < len; l++) {
            for(int i = 0; i < len - l; i++) {
                int j = i + l;
                if(s[i] == s[j] && (l < 2 || p[i+1][j-1])) {
                    p[i][j] = true;
                    if(l + 1 > maxLen) {
                        maxLen = l + 1;
                        ans = s.substr(i, l+1);
                    }
                }
            }
        }
        return ans;
    }
};

 本方法的时间复杂度为O(n2),空间复杂度为O(n),运行时间为108ms。

 

方法三:中心扩展法

中心扩展法的核心思想是选定一个中心,并不断向两端扩展来判断是否是回文字符串。

对于长度为n的字符串,共有2n-1个中心:首先,可以选定每个字符为中心,并不断向两端扩展,共有n中选法,此时选定的是“aba”型的回文字符串;其次,可以选定每对字符中间位置为中心,共有n-1中选法,此时选定的是“abba”型回文字符串。

class Solution {
public:
    string longestPalindrome(string s) {
        int len = s.length();
        if(len == 0 || len == 1)
            return s;
        string ans;
        int maxLen = 0;
        for(int i = 0; i < len - 1; i++) {
            int len1 = isPalindrome(s, i, i);
            if(len1 > maxLen) {
                maxLen = len1;
                ans = s.substr(i - len1 / 2, len1);
            }
            int len2 = isPalindrome(s, i, i + 1);
            if(len2 > maxLen) {
                maxLen = len2;
                ans = s.substr(i + 1- len2 / 2, len2);
            }
        }
        return ans;
    }
    
    int isPalindrome(string s, int start, int end) {
        int len = s.length();
        while(start >= 0 && end < len) {
            if(s[start] == s[end]) {
                start--;
                end++;
            } else {
                break;
            }
        }
        return end - start - 1;
    }
};

 本方法的时间复杂度为O(n2),空间复杂度为O(n),运行时间为12ms。

posted @ 2018-08-14 18:13  双肩包码农  阅读(76)  评论(0编辑  收藏  举报