[编程之美]回文字符序列
描述
给定字符串,求它的回文子序列个数。回文子序列反转字符顺序后仍然与原序列相同。例如字符串aba中,回文子序列为"a", "a", "aa", "b", "aba",共5个。内容相同位置不同的子序列算不同的子序列。
输入
第一行一个整数T,表示数据组数。之后是T组数据,每组数据为一行字符串。
输出
对于每组数据输出一行,格式为"Case #X: Y",X代表数据编号(从1开始),Y为答案。答案对100007取模。
数据范围
1 ≤ T ≤ 30
小数据
字符串长度 ≤ 25
大数据
字符串长度 ≤ 1000
- 样例输入
-
5 aba abcbaddabcba 12111112351121 ccccccc fdadfa
- 样例输出
-
Case #1: 5 Case #2: 277 Case #3: 1333 Case #4: 127 Case #5: 17
初步想法是动态规划,用dp[i][j]表示s[i...j]之间的回文子序列的个数。
考虑dp[i][j]和dp[i][j - 1]的情况,dp[i][j]肯定包含dp[i][j - 1]的所有回文子序列。并且,当s[j]与s[i..j - 1]中的某个字符相同时,则会产生新的回文序列。
因此 dp[i][j] = dp[i][j - 1] + dp[k][j - 1] + 1, 其中s[k] == s[j - 1]。
考虑到需要遍历i, j, k三个下表,时间复杂度是o(n3),显然会超时。
参考其他人的题解,若s[j]与s[i + 1...j - 1]中的某个字符相同而产生的新的回文序列其实是已经包含在dp[i + 1][j]中,因此没有必要重复求解。
如果s[j] != s[i],那么dp[j][i] = dp[j][i - 1] + dp[j + 1][i] - dp[j + 1][i - 1]。此时回文序列分为三类,即包含s[j]的,包含s[i]的,以及都不包含的,根据集合原理可以得出解。
如果s[j] == s[i],此时dp[j][i] = dp[j][i - 1] + dp[j + 1][i] - dp[j + 1][i - 1] + dp[j + 1][i - 1] + 1,最后两项表示以s[i]和s[j]为两端组成的新的回文序列。
此时复杂度降为o(n2)