本文主要是介绍统计不同回文子字符串--LeetCode730:分析清晰,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
统计不同回文子字符串–LeetCode730
题目
给定一个字符串 S,找出 S 中不同的非空回文子序列个数,并返回该数字与 10^9 + 7
的模。通过从 S 中删除 0 个或多个字符来获得子字符序列。如果一个字符序列与它反转后的字符序列一致,那么它是回文字符序列。如果对于某个 i
,A_i != B_i
,那么 A_1, A_2, ...
和 B_1, B_2, ...
这两个字符序列是不同的。
示例 1:
输入:
S = 'bccb'
输出:6
解释:
6 个不同的非空回文子字符序列分别为:'b', 'c', 'bb', 'cc', 'bcb', 'bccb'。
注意:'bcb' 虽然出现两次但仅计数一次。
示例 2:
输入:
S = 'abcdabcdabcdabcdabcdabcdabcdabcddcbadcbadcbadcbadcbadcbadcbadcba'
输出:104860361
解释:
共有 3104860382 个不同的非空回文子字符序列,对 10^9 + 7 取模为 104860361。
提示:
- 字符串 S 的长度将在[1, 1000]范围内。
- 每个字符 S[i] 将会是集合 {‘a’, ‘b’, ‘c’, ‘d’} 中的某一个。
思路
状态定义:dp[i][j]
表示s[i, j]
中回文子序列的个数。
转移方程:
- 如果
s[i] != s[j]
,则有dp[i][j] = dp[i][j - 1] + dp[i + 1][j] - dp[i + 1][j - 1]
,dp[i + 1][j - 1]
在dp[i][j - 1]
和dp[i+1][j]
中都有,所以要减去一个。 - 如果
s[i] = s[j] = c
,则有dp[i][j] = 2 * dp[i + 1][j - 1]
,乘以2意思是在s[i + 1, j - 1]
中所有的回文子序列两边加上c,就构成了新的回文子序列,原来有dp[i + 1][j - 1]
这么多个,两边加上c之后增加了dp[i + 1][j - 1]
个回文子序列,所以乘以2得到当前的dp[i][j]
。
但是上述s[i] = s[j]
情况下,结果存在重复计算和疏漏,需要进行去重和补充。
- 如果在
s[i + 1, j - 1]
没有字符c,需要进行补充,即dp[i][j] += 2
,补上的是[c], [c, c]; - 如果在
s[i + 1, j - 1]
只有一个字符c,需要进行补充,即dp[i][j] += 1
,补上的是[c, c]; - 如果在
s[i + 1, j - 1]
有两个或多个字符c,需要进行去重,即dp[i][j] -= dp[l + 1][r - 1]
,l
是i
的左边第一个字符为c的位置,r
是j
的右边第一个字符为c的位置。
初始条件:
dp[n - 1][n - 1] = 1
表示单个字符就是一个回文子序列dp[i][i - 1] = 0
表示字符串为空
最终答案就是dp[0][n-1]
参考题解:
阿飞的题解
想想大司马会怎么做的题解
代码如下(用时69ms):
class Solution {public int countPalindromicSubsequences(String S) {if (S == null || S.length() == 0) {return 0;}int n = S.length();int mod = 1000000000+7;int[][] dp = new int[n][n];for (int i = 0; i < n; i++) {dp[i][i] = 1;}for (int i = n-2; i >= 0; i--) {for (int j = i+1; j < n; j++) {if (S.charAt(i) == S.charAt(j)) {dp[i][j] = 2*dp[i+1][j-1];int left = i+1;int right = j-1;while (left <= right && S.charAt(i) != S.charAt(left)) left++;while (left <= right && S.charAt(j) != S.charAt(right)) right--;if (left > right) {dp[i][j] += 2;} else if (left == right) {dp[i][j] += 1;} else {dp[i][j] -= dp[left+1][right-1];}}else {dp[i][j] = dp[i+1][j]+dp[i][j-1]-dp[i+1][j-1];}dp[i][j] = (dp[i][j] < 0) ? dp[i][j]+mod : dp[i][j]%mod;}}return dp[0][n-1];}
}
这篇关于统计不同回文子字符串--LeetCode730:分析清晰的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!