LeetCode 5. Longest Palindromic Substring / 516. Longest Palindromic Subsequence

5. Longest Palindromic Substring

暴力的话需要枚举开始下标i,结束下标j,并判断该字串是否为回文,需要O(n^3)时间。很明显,通过暴力并判断字串是否为回文效率很低,其并没有考虑到回文的性质。

 

方法一:DP

bool dp[i][j] 表示下标 i~j 的字串是否为回文

考虑到回文的特性,递推公式很容易得到: dp[i][j] = ( dp[i+1][j-1]==ture && s[i]==s[j] )

Base cases 也很容易想,dp[i][i] = true,   dp[i][i+1] = ( s[i]==s[i+1] )    for all i

有一点需要注意的是,通过递推更新 dp[i][j] 的时候,i 需要从后向前遍历。可以结合dp矩阵的图想一下,这是由于每个点更新都需要依赖左下角的点,如果i从前向后遍历左下角的点有可能还没更新。

或者更新的时候用一个variable len,枚举i,然后j=i+len,从小到大构建。

class Solution {
public:
    string longestPalindrome(string s) {
        int n=s.size();
        bool dp[n][n]={false};
        
        for (int i=0;i<n;++i) dp[i][i]=true;
        for (int i=0;i+1<n;++i) dp[i][i+1]=(s[i]==s[i+1]);
             
        for (int i=n-1-2;i>=0;--i)
            for (int j=i+2;j<n;++j)
                dp[i][j] = (dp[i+1][j-1] && s[i]==s[j]);      
            
        string res="";
        for (int i=0;i<n;++i){
            for (int j=i;j<n;++j){
                if (dp[i][j] && j-i+1>res.size()) 
                    res=s.substr(i,j-i+1);
            }
        }
        
        return res;
    }
};

 

方法二:

考虑到回文的特性,枚举每一个回文的中心点,向两边扩展。对于长度为n的字符串,需要枚举2n-1个中心点。时间复杂度是O(n^2),但是空间复杂度为O(1),优于DP。

class Solution {
public:
    string longestPalindrome(string s) {
        int n=s.size();
        string res="";
        
        int left, right;
        for (int i=0;i<n;++i){
            left=right=i;
            while (left-1>=0 && right+1<n && s[left-1]==s[right+1]){--left; ++right;}
            if (right-left+1 > res.size()) 
                res=s.substr(left,right-left+1); 
        }
        
        for (int i=0;i<n-1;++i){
            left=i; right=i+1;
            if (s[left]!=s[right]) continue;
            while (left-1>=0 && right+1<n && s[left-1]==s[right+1]){--left; ++right;}
            if (right-left+1 > res.size()) 
                res = s.substr(left,right-left+1);
        }
        
        return res;
    }
};

 

516. Longest Palindromic Subsequence

dp[i][i+1] 可以并到for循环里一起处理。

class Solution {
public:
    int longestPalindromeSubseq(string s) {
        int n=s.size();
        if (n==0) return 0;
        
        // dp[i][i] = 1;
        // dp[i][j] = max dp[i+1][j-1]+2 if s[i]==s[j]
        //                dp[i+1][j]
        //                dp[i][j-1]             
        vector<vector<int>> dp(n,vector<int>(n,0));
        for (int i=0;i<n;++i) dp[i][i]=1;
        
        for (int len=1;len<n;++len){
            for (int i=0;i+len<n;++i){
                int j=i+len;
                if (s[i]==s[j]) dp[i][j]=dp[i+1][j-1]+2;
                else dp[i][j]=max(dp[i+1][j],dp[i][j-1]);
            }
        }
        return dp[0][n-1];
    }
};

 

posted @ 2018-07-16 20:46  約束の空  阅读(143)  评论(0)    收藏  举报