博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【动态规划】回文子序列个数
阅读量:5008 次
发布时间:2019-06-12

本文共 3255 字,大约阅读时间需要 10 分钟。

Description

给定一个字符序列,求这个序列中回文子序列的个数。

Input

包含多组用例,每个用例为一行字符序列(只含有字母和数字,不包含空格,字符串长度小于100)。

Output

输出该字符序列中回文子序列的个数。

Sample Input

aaaa aaba

Sample Output

15 10

HINT

对于样例2,有如下回文子序列(为便于观察,我们另字符序列为a1 a2 b a3):
a1
a2
b
a3
a1 a2
a1 a3
a2 a3
a1 b a3
a2 b a3
a1 a2 a3

 

思路方法与代码均转载自 http://www.cnblogs.com/AndyJee/p/4465696.html (侵删)

参考 http://blog.csdn.net/piaocoder/article/details/51066568 (侵删)

 

思路

动态规划思想

对于任意字符串,如果头尾字符不相等,则字符串的回文子序列个数就等于去掉头的字符串的回文子序列个数+去掉尾的字符串的回文子序列个数-去掉头尾的字符串的回文子序列个数;如果头尾字符相等,那么除了上述的子序列个数之外,还要加上首尾相等时新增的子序列个数,1+去掉头尾的字符串的回文子序列个数,1指的是加上头尾组成的回文子序列,如aa,bb等。

因此动态规划的状态转移方程为:

设字符串为str,长度为n,p[i][j]表示第i到第j个字符间的最长子序列的长度(i<=j),则:

状态初始条件:dp[i][i]=1 (i=0:n-1)

状态转移方程:dp[i][j]=dp[i+1][j] + dp[i][j-1] - dp[i+1][j-1]  if(str[i]!=str[j])

                   dp[i][j]=dp[i+1][j] + dp[i][j-1] - dp[i+1][j-1]+dp[i+1][j-1]+1=dp[i+1][j] + dp[i][j-1]+1  if (str[i]==str[j])

 

对任意字符串,如果头和尾相同,那么它的最长回文子序列一定是去头去尾之后的部分的最长回文子序列加上头和尾。如果头和尾

不同,那么它的最长回文子序列是去头的部分的最长回文子序列和去尾的部分的最长回文子序列的较长的那一个。

设字符串为str,dp(i,j)表示str[i..j]的最长回文子序列。

状态转移方程如下:

当i > j时,dp[i,j]= 0。

当i = j时,dp[i,j] = 1。

当i < j并且str[i] == str[j]时,dp[i][j] = dp[i+1][j-1]+2;

当i < j并且str[i] ≠ str[j]时,dp[i][j] = max(dp[i][j-1],dp[i+1][j]);

注意如果i+1 == j并且str[i] == str[j]时,dp[i][j] = dp[i+1][j-1]+2 = dp[j,j-1]+2 = 2,这就是“当i > j时f(i,j)=0”的好处。

由于dp[i][j]依赖i+1,所以循环计算的时候,第一维必须倒过来计算,从len-1到0。

最后,s的最长回文子序列长度为dp[0][len-1]。

 

代码(未ac)

#include 
#include
using namespace std;int NumOfPalindromeSubSequence(string str){ int len=str.length(); vector
> dp(len,vector
(len)); for(int j=0;j
=0;i--){ dp[i][j]=dp[i+1][j]+dp[i][j-1]-dp[i+1][j-1]; if(str[i]==str[j]) dp[i][j]+=1+dp[i+1][j-1]; } } return dp[0][len-1];}int main(){ string str; int num; while(cin>>str){ num=NumOfPalindromeSubSequence(str); cout<
<

 

于是向学霸copy了一段能ac的代码 如下 

 

#include 
//用来求最长回文子序列的长度#include
#include
#include
#include
#define MAXSIZE 105#define vi vector
#define vvi vector
> #define vll vector
#define vvll vector
> using namespace std;long LengthofLongestPalindlrome(char ch[]) { long len = strlen(ch); vvi dp(len, vi(len)); for (int j = 0; j < len; j++) { dp[j][j] = 1;//开始漏掉了,结果错误 for (int i = j - 1; i >= 0; i--) { if (ch[i] == ch[j]) { dp[i][j] = dp[i + 1][j - 1] + 2; } else { dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]); } } } return dp[0][len - 1];}long long NumOfPalinrome(char ch[]) { long long len = (long long)strlen(ch); vvll dp(len, vll(len)); for (int j = 0; j < len; j++) { dp[j][j] = 1;//开始漏掉了,结果错误 for (int i = j - 1; i >= 0; i--) { dp[i][j] = dp[i + 1][j]+dp[i][j-1] -dp[i+1][j-1]; if (ch[i] == ch[j]) { dp[i][j] +=1+ dp[i + 1][j-1];//注意这里!!! } } } return dp[0][len - 1];}int main() { //string str; char ch[MAXSIZE]; //int dp[MAXSIZE][MAXSIZE]; while (cin>>ch) //while(scanf_s("%s",ch)!=EOF) { //int length = LengthofLongestPalindlrome(ch); long long length2 = NumOfPalinrome(ch); //cout << length << endl; cout << length2 << endl; } return 0;}

 

 

转载于:https://www.cnblogs.com/cbhhh/p/6013553.html

你可能感兴趣的文章
学习 WCF (1)--基础篇
查看>>
sql server 2008学习4 设计索引的建议
查看>>
vim 插件之vundle
查看>>
数据库多对多关联表(Python&MySQL)
查看>>
[实变函数]1.2 集合的运算
查看>>
第06天
查看>>
设计模式的征途—5.原型(Prototype)模式
查看>>
Fiddler中添加serverIP
查看>>
mysql的某个数据库拒绝访问的问题
查看>>
C# ~ 从 XML 到 Linq 到 Linq to XML
查看>>
常用汉字的五笔拆法
查看>>
1044: [HAOI2008]木棍分割 - BZOJ
查看>>
资源:数据库原理
查看>>
后进先出 stack、 先进先出Queue
查看>>
来常工富藤的第一天
查看>>
你想到了,就有别人去实现,那你为什么不去实现呢
查看>>
OSI与TCP/IP模型
查看>>
【IT笔试面试题整理】丑数
查看>>
敏捷开发一千零一问系列之六:业务人员怎样参与开发?
查看>>
双向链表
查看>>