问题
题目:[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);
}
};