Problem Description
Given a string S, find the number of different non-empty palindromic subsequences in S, and return that number modulo 10^9 + 7.
A subsequence of a string S is obtained by deleting 0 or more characters from S.
A sequence is palindromic if it is equal to the sequence reversed.
Two sequences A_1, A_2, … and B_1, B_2, … are different if there is some i for which A_i != B_i.
Example 1:
Input:
S = ‘bccb’
Output: 6
Explanation:
The 6 different non-empty palindromic subsequences are ‘b’, ‘c’, ‘bb’, ‘cc’, ‘bcb’, ‘bccb’.
Note that ‘bcb’ is counted only once, even though it occurs twice.
Example 2:
Input:
S = ‘abcdabcdabcdabcdabcdabcdabcdabcddcbadcbadcbadcbadcbadcbadcbadcba’
Output: 104860361
Explanation:
There are 3104860382 different non-empty palindromic subsequences, which is 104860361 modulo 10^9 + 7.
Note:
The length of S will be in the range [1, 1000].
Each character S[i] will be in the set {‘a’, ‘b’, ‘c’, ‘d’}
建立递推关系
用dp[i][j]表示字符串中下标从i到j的范围内不同回文子串个数,首先分析如下例子,以此来推导递推关系式
在字符串S中,若S[i]!=S[j],dp[i][j]=dp[i][j-1]+dp[i+1][j]-dp[i+1][j-1]
若S[i]==S[j],则分以下三种情况:
若S[i+1]~S[j-1]之间没有字符等于S[i],则dp[i][j]=dp[i+1][j-1]*2+2
若S[i+1]~S[j-1]之间有一个字符等于S[i],则dp[i][j]=dp[i+1][j-1]*2+1
若S[i+1]~S[j-1]之间至少有两个字符等于S[i],则dp[i][j]=dp[i+1][j-1]*2-dp[ii+1][jj-1],其中ii为第一个等于S[i]的字符的下标,jj为最后一个等于S[i]的字符的下标。
代码如下
#include <iostream>
#include <string>
#define MAXN 1000
using namespace std;
int dp[MAXN][MAXN];
long int M=1E9+7;
int countPalindromicSubsequences(string S) {
int n=S.length();
for(int i=0;i<n;i++)
dp[i][i]=1; //dp[i][j]表示字符串中下标从i到j的不同回文子串个数
for(int len=1;len<n;len++)
for(int i=0;i<n-len;i++)
{
int j=i+len;
if(S[i]==S[j])
{
int ii=i+1;
while(S[ii]!=S[i])
ii++;
int jj=j-1;
while(S[jj]!=S[j])
jj--;
if(ii==jj)
dp[i][j]=dp[i+1][j-1]*2+1; //若s[i+1]到s[j-1]之间只有一个s[i]
else if(ii>jj)
dp[i][j]=dp[i+1][j-1]*2+2; //若s[i+1]到s[j-1]之间没有s[i]
else
dp[i][j]=dp[i+1][j-1]*2-dp[ii+1][jj-1]; //若s[i+1]到s[j-1]之间至少有两个s[i],其中ii为第一个s[i]的下标,jj为最后一个s[i]的下标
} //if
else
dp[i][j]=dp[i][j-1]+dp[i+1][j]-dp[i+1][j-1];
dp[i][j]=(dp[i][j]+M)%M; //在取余数情况下,要避免减法运算结果出现负数
} //for
return dp[0][n-1];
}