题目
给定字符串,求它的回文子序列个数。
具体描述请见hihoCoder。
解题思路
本题与求最长回文子序列很类似,只要在算法上稍作修改即可。
仍然采用动态规划的思想。在求f[i,
j]时,注意到包含第i个字符且不包含第j个字符的回文子序列个数为f[i, j-1] -
f[i+1, j-1],包含第j个字符且不包含第i个字符的回文子序列个数为f[i+1, j] -
f[i+1, j-1],均不包含则是f[i+1, j-1],均包含则是f[i+1, j-1] +
1。因此列出递推式:
f[i, j] = f[i, j-1] + f[i+1, j] - f[i+1, j-1] 如果str[i] != str[j]
f[i, j] = f[i, j-1] + f[i+1, j] + 1 如果str[i] == str[j]
注意,凡是涉及到动态规划的问题最好都要画出递推进行的矩阵,弄明白起始点和结束点,以及递推方向。
时间复杂度
时间复杂度为N2,空间复杂度为N2,可进一步优化为2N。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| #include <iostream> #include <string> using namespace std;
int calSum(string str) { int N = str.size(); int** S = new int*[N]; for (int i = 0; i < N; i++) { S[i] = new int[N]; for (int j = 0; j < N; j++) S[i][j] = 0; S[i][i] = 1; } for (int i = N - 2; i >= 0; i--) { for (int j = i + 1; j < N; j++) { S[i][j] = (S[i + 1][j] + S[i][j - 1] - S[i + 1][j - 1]); if (str[i] == str[j]) S[i][j] += S[i + 1][j - 1] + 1; S[i][j] = (S[i][j] + 100007) % 100007; } }
return S[0][N - 1]; }
int main() { int T = 0; cin >> T; for (int i = 1; i <= T; i++) { string str; cin >> str;
cout << "Case #" << i << ": " << calSum(str) << endl; }
return 0; }
|