最长回文子序列LPS(Longest Palindromic Subsequence)也是编程题目里面经常出现的一种,但是更经常出现的是最长回文子串(Longest Palindromic Substring),英文简写都是LPS,所以在搜索的时候不要搞混了。
主要区别
子串是连续的,字符之间不能有间隔;而子序列可以是不连续的。如字符串cabbeaf,它的最长回文子串是bb,而最长回文子序列是abba。
输入一个字符串,然后输出最长回文子序列的长度。
假设S[0…n-1]是给定的字符串序列,长度为n,用lps(0,n-1)表示序列S[0…n-1]的最长回文子序列的长度。
1)如果S长度为1,那么最长回文自序列就是1;
2)如果S最后一个字符和第一个字符相同,则lps(0,n-1)=lps(1,n-2)+2;以字符串“1324332431”为例,第一个字符与最后一个字符相同,lps(1,n-2)表示红色部分的最长回文子序列的长度;
3)如果S的最后一个字符与第一个字符不同,则lps(0,n-1)=max(lps(1,n-1),lps(0,n-2));以字符串“32433243”为例,lps(1,n-1)表示去掉第一字符的子序列,lps(0,n-2)表示去掉最后一个字符的子序列。
时间复杂度为O(2^n) ,空间复杂度O(n)。
//LPS(Longest Palindromic Subsequence)
//Date:2016-04-04
//Author:Sin_Geek
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int lps(const string &str, int begin, int end)
{
//begin大于end时返回0
if (begin > end)
return 0;
//只有一个字符,回文长度为1
if (begin == end)
return 1;
//首尾相同
if (str[begin] == str[end])
return lps(str, begin + 1, end - 1) + 2;
//首尾不同
return max(lps(str, begin, end - 1), lps(str, begin + 1, end));
}
int main()
{
string str;
cin >> str;
cout << lps(str, 0, str.size() - 1) << endl;
return 0;
}
时间复杂度为O(n^2) ,空间复杂度O(n^2)。
//LPS(Longest Palindromic Subsequence)
//Date:2016-04-04
//Author:Sin_Geek
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int lps(const string &str, int begin, int end, vector<vector<int>> &f)
{
//begin大于end时返回0
if (begin > end)
return 0;
//只有一个字符,回文长度为1
if (begin == end)
return f[begin][end] = 1;
//如果子串str[begin...end]已经计算过,避免计算直接返回
if (f[begin][end])
return f[begin][end];
//首尾相同
if (str[begin] == str[end])
return f[begin][end] = lps(str, begin + 1, end - 1, f) + 2;
//首尾不同
return f[begin][end] = max(lps(str, begin, end - 1, f), lps(str, begin + 1, end, f));
}
int main()
{
string str;
cin >> str;
int n = str.size();
vector<vector<int>> f(n, vector<int>(n, 0));
cout << lps(str, 0, n-1, f) << endl;
return 0;
}
时间复杂度为O(n^2) ,空间复杂度O(n^2)。
//LPS(Longest Palindromic Subsequence)
//Date:2016-04-04
//Author:Sin_Geek
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
string str;
cin >> str;
int n = str.size();
//创建二维数组f[i][j]表示str[i..j]的最长回文子序列。
vector<vector<int>> f(n,vector<int>(n));
for (int i = n - 1; i >= 0; --i)
{
f[i][i] = 1;
for (int j = i + 1; j < n; ++j)
if (str[i] == str[j])
f[i][j] = f[i + 1][j - 1] + 2;
else
f[i][j] = max(f[i][j - 1], f[i + 1][j]);
}
cout << f[0][n - 1] << endl;
return 0;
}
上面的那个自顶向上动态规划版本,空间复杂度为O(n^2),其实计算第i行时只用到了第i+1行,跟其他的无关,所以只需要2行即可。
可以先在第0行计算f[n-1],然后用第0行的结果在第1行计算f[n-2],再用第1行的结果在第0行计算f[n-3],以此类推。正在计算的那行设为now,那么计算第now行时,就要用第1-now行的结果。当计算完成时,如果s.length()是奇数,则结果在第0行;如果是偶数,则结果在第1行。
时间复杂度为O(n^2) ,空间复杂度O(n)。
//LPS(Longest Palindromic Subsequence)
//Date:2016-04-04
//Author:Sin_Geek
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
string str;
cin >> str;
int n = str.size(), now = 0;
//创建二维数组f[i][j]表示str[i..j]的最长回文子序列。
vector<vector<int>> f(2, vector<int>(n));
for (int i = n - 1; i >= 0; --i)
{
f[now][i] = 1;
for (int j = i + 1; j < n; ++j)
if (str[i] == str[j])
f[now][j] = f[1 - now][j - 1] + 2;
else
f[now][j] = max(f[now][j - 1], f[1 - now][j]);
now = 1 - now;
}
if (n % 2 == 0)
cout << f[1][n - 1] << endl;
else
cout << f[0][n - 1] << endl;
return 0;
}