leetcode-5-Longest Palindromic Substring 动态规划

问题

题目:[leetcode-5]

思路

朴素的思路,暴力法。但是考虑从较长的串开始枚举。不过还是TLE.

代码

/*
这次我还是暴力,但是从大串向小串枚举。
之前的枚举思路导致TLE,这次的可能也导致。试试吧。
*/

class Solution {
public:
    string longestPalindrome(string s) {
        int sz = s.size();
        if(!sz)
            return "";

        for( int len = sz; len > 0; --len )
        {
            for( int start = 0; start + len <= sz; ++start )
            {
                std::string tmp( s.begin() + start, s.begin() + start + len );
                if( is_palindrome(tmp) )
                    return tmp;
            }
        }
        return std::string( s.begin(), s.begin() + 1 );
    }
private:
    bool is_palindrome( const std::string& s ){
        return std::equal( s.begin(), s.end(), s.rbegin() );
    }    
};

思路1

先著名,DP的方法我没有想到。看了别人的解释才明白的。
自己没想到的原因是,思路一致现在在一维的dp数组,向lis问题靠近。其实,字符串这一块用二维的情形也非常多。还有答案解法的状态定义很精髓。

DP问题的套路写在注释里面了。
说一个注意点:就是打表的顺序。DP的打表顺序是自底向上,但是两层for循环不见得是按着下标顺序依次打表。比如,dp[i][j] = dp[i+1][j-1] && (s[i]==s[j]) , j-i>1。分析这个状态转移,状态[i , j]依赖于状态[ i + 1, j - 1 ]。但是状态[ i + 1, j - 1 ]在状态[i,j]的左下方。 所以打表的时候i需要从下到上,j还是从左到右。
这里写图片描述

下面给出dp的状态图:
这里写图片描述

代码1

/*
状态定义:dp[i][j]:表示从s[i...j]是否是回文串。
转移方程:
dp[i][j] = dp[i+1][j-1] && (s[i]==s[j]) , j-i>1
dp[i][j] = (s[i]==s[j]) , j - i = 1
初始化:
dp[i][i] = 1
打表

当然,这个转移方程稍微有一点弯。分类讨论的情形要考虑,还有转移方程没有想到主要是状态定义限制在一维了。
其实字符串这一块题目,很多状态转移方程都是二维。

*/


class Solution {
public:
    string longestPalindrome(string s) {
        int sz = s.size();
        if(!sz)
            return 0;

        std::vector< std::vector<int> > dp( sz, std::vector<int>(sz, int()) );
        for( int i = 0; i < sz; ++i )
        {
            dp[i][i] = 1;
        }

        for( int i = sz-1; i >= 0; --i )
        {
            for( int j = i + 1; j < sz; ++j )
            {
                if( j == i + 1 )
                    dp[i][j] = (s[i]==s[j]);
                else
                    dp[i][j] = ( (dp[i+1][j-1]) && (s[i] == s[j])); 

            }
        }
        int max = 0;
        int start = 0;
        for( int i = 0; i < sz; ++i )
        {
            for( int j = i; j < sz; ++j )
            {
                if( dp[i][j] )
                {
                    if(j-i+1>max)
                    {
                        max = j-i+1;
                        start = i;
                    }
                }
            }
        }

        return s.substr(start,max);
    }
};

思路1

还是上面的办法,dp的意义变了点。

代码1

class Solution {
public:
    string longestPalindrome(string s) {
        int sz = s.size();
        if(!sz) return "";
        if(1==sz) return string(1, s[0]);

        std::vector< std::vector<int> > dp(sz, std::vector<int>(sz, int()));
        for( int i = 0; i < sz; ++i ) dp[i][i] = 1;

        int max = 0;
        int start , len = 0;
        for(int i = sz-1; i >= 0; --i){
            for(int j = i + 1; j < sz; ++j){
                if(j == i + 1) dp[i][j] = (s[i]==s[j])?2:0;
                else dp[i][j] = (dp[i+1][j-1]>0&&s[i]==s[j])?dp[i+1][j-1] + 2:0;

                if(dp[i][j] > max){
                    max = dp[i][j];
                    start=i;
                    len = max;
                }
            }
        }
        if(!max) return string(1, s[0]);
        else return s.substr(start, len);
    }
};
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值