最长回文子序列/最长回文子串(DP,马拉车)
字符子串和字符子序列的区别
字符字串指的是字符串中连续的n个字符;如palindrome中,pa,alind,drome等都属于它的字串
而字符子序列指的是字符串中不一定连续但先后顺序一致的n个字符;如palindrome中,plind,lime属于它的子序列,而mod,rope则不是,因为它们与字符串的字符顺序不一致。
Manacher's Algorithm
在计算机科学中,最长回文子串或最长对称因子问题是在一个字符串中查找一个最长的连续的回文的子串,例如“banana”最长回文子串是“anana”。最长回文子串并不一定是唯一的,比如“abracadabra”,没有超过3的回文子串,但是有两个回文字串长度都是3:“ada”和“aca”。在一些应用中,我们求出全部的极大回文子串(不被其他回文串包含的回文子串)。
Manacher于[1]发现了一种线性时间算法,可以在列出给定字符串中从任意位置开始的所有回文子串。并且,Apostolico, Breslauer & Galil [2]发现,同样的算法也可以在任意位置查找全部极大回文子串,并且时间复杂度是线性的。因此,他们提供了一种时间复杂度为线性的最长回文子串解法。另外,Jeuring (1994)[3], Gusfield (1997)[4]发现了基于后缀树的算法。也存在已知的高效并行算法。
最长回文子串算法不应当与最长回文子序列算法混淆。
要在线性时间内找出字符串的最长回文子串,这个算法必须利用回文和子回文的这些特点和观察
C++实现
- constexpr auto MAXN = (int);
- char s[MAXN << ], str[MAXN];
- int RL[MAXN];
- int Manacher(void) {
- size_t len = strlen(str); *s = '#';
- for (int i = ; i < len; i++) {
- s[(i << ) + ] = str[i]; s[(i << ) + ] = '#';
- }len = (len << ) + ;
- int max = , pos, maxRight = -; memset(RL, , sizeof(RL));
- for (int i = ; i < len; i++) {
- if (i < maxRight) RL[i] = std::min(RL[(pos << ) - i], maxRight - i);
- else RL[i] = ;
- while (i - RL[i] >= && i + RL[i] < len && s[i - RL[i]] == s[i + RL[i]])++RL[i];
- if (i + RL[i] > maxRight) { pos = i; maxRight = i + RL[i]; }
- max = std::max(max, RL[i] - );
- } return max;
- }
具体实现过程演示
- #include<cstring>
- #include<cstdio>
- #include<iostream>
- #include<algorithm>
- #include<cmath>
- #include<queue>
- #define lson l,mid,idx<<1
- #define rson mid+1,r,idx<<1|1
- #define lc idx<<1
- #define rc idx<<1|1
- #define N 100010
- #define ll long long
- using namespace std;
- char str[N],s[N];
- int len[N]={};
- int manachr(){
- s[]='$';
- int n=;
- for(int i=;str[i];i++)s[n++]='#',s[n++]=str[i];
- s[n++]='#';s[n]='\0';
- int MAX=,id=,mix=;
- for(int i=;i<n;i++){
- if(i<mix)len[i]=min(len[*id-i],mix-i);
- else len[i]=;
- while(s[i-len[i]]==s[i+len[i]])len[i]++;
- if(len[i]+i>mix)mix=len[i]+i,id=i,MAX=max(MAX,len[i]);
- }
- for(int i=;i<n;i++)printf("len[%d]=%d\n",i,len[i]);
- return MAX-;
- }
- //mix 为id为中心 回文串最右端 当i<mix 时
- // 利用回文串的性质 len[i]=len[id-(i-id)] 考虑到i会超过mix 和mix-i取最小
- //
- int main(int argc, char const *argv[])
- {
- cin >> str;
- cout << manachr() << endl;
- return ;
- }
MATLAB实现
- function m = Manacher(a)
- T = ['$#' reshape([a;ones(size(a))*'#'], , '') '@'];
- l = length(T);
- P = zeros(, l);
- mx = ; %range
- id = ; %center
- for i = :l-
- if i < mx
- P(i) = min(P( * id - i), mx - i);
- else
- P(i) = ;
- end
- while T(i+P(i)) == T(i-P(i))
- P(i) = P(i) + ;
- end
- if P(i) + i > mx
- mx = P(i) + i;
- id = i;
- end
- end
- m = max(P)-;
最长回文子序列
分析
对任意字符串,如果头和尾相同,那么它的最长回文子序列一定是去头去尾之后的部分的最长回文子序列加上头和尾。如果头和尾不同,那么它的最长回文子序列是去头的部分的最长回文子序列和去尾的部分的最长回文子序列的较长的那一个。
str[0...n-1]是给定的字符串序列,长度为n,假设f(0,n-1)表示序列str[0...n-1]的最长回文子序列的长度。
1.如果str的最后一个元素和第一个元素是相同的,则有:f(0,n-1)=f(1,n-2)+2;例如字符串序列“AABACACBA”,第一个元素和最后一个元素相同,其中f(1,n-2)表示红色部分的最长回文子序列的长度;
2.如果str的最后一个元素和第一个元素是不相同的,则有:f(0,n-1)=max(f(1,n-1),f(0,n-2));例如字符串序列“ABACACB”,其中f(1,n-1)表示去掉第一元素的子序列,f(0,n-2)表示去掉最后一个元素的子序列。
设字符串为s,f(i,j)表示s[i..j]的最长回文子序列。
状态转移方程如下:
当i>j时,f(i,j)=0。
当i=j时,f(i,j)=1。
当i<j并且s[i]=s[j]时,f(i,j)=f(i+1,j-1)+2。
当i<j并且s[i]≠s[j]时,f(i,j)=max( f(i,j-1), f(i+1,j) )。
由于f(i,j)依赖i+1,所以循环计算的时候,第一维必须倒过来计算,从s.length()-1到0。
最后,s的最长回文子序列长度为f(0, s.length()-1)。
以"BBABCBCAB"为例:
(注:本程序的填表方向斜向左上,即每次从最后一行最后一个数开始,依次向左填写)
C++实现
- int dp[][];
- char str[N];
- // dp[i][j] 代表 str[i]到str[j] 中回文子序列的最大长度
- // str[i]==str[j] dp[i][j]=dp[i+1][j-1]+2;
- // str[i]!=str[j] dp[i][j]=max(dp[i][j-1],dp[i+1][j]);
- int main(){
- cin>>(str+);
- int n=strlen(str+);
- for(int i=n;i>=;i--){
- dp[i][i]=;
- for(int j=i+;j<=n;j++){
- if(str[i]==str[j])dp[i][j]=dp[i+][j-]+;
- else dp[i][j]=max(dp[i+][j],dp[i][j-]);
- }
- }
- cout<<dp[][n]<<endl;
- }
为进一步减小空间复杂度,我们发现计算第i行时只用到了第i+1行,这样我们便不需要n行,只需要2行即可。
滚动数组优化
- #include <iostream>
- #include <bits/stdc++.h>
- using namespace std;
- int dp[][];
- int main()
- {
- string str;
- while(cin >> str)
- {
- int len = str.length();
- memset(dp,,sizeof(dp));
- int cur = ;
- for(int i = len - ; i >= ; i--)
- {
- cur ^= ;
- dp[cur][i] = ;
- for(int j = i + ; j < len; j++)
- {
- if(str[i] == str[j])
- dp[cur][j] = dp[cur^][j-] + ;
- else
- dp[cur][j] = max(dp[cur][j-],dp[cur^][j]);
- }
- }
- cout<<dp[cur][len-]<<endl;
- }
- }
最长回文子序列/最长回文子串(DP,马拉车)的更多相关文章
- hdu6537 /// DP 最长不降子序列->最长公共子序列
题目大意: 给定一个字符串 字符为0~9 求翻转某个区间后使得串中的最长不降子序列最长 因为字符范围为0~9 假设有一个 0 1 2 3 4 5 6 7 8 9 的序列 此时翻转某个区间得到形如 0 ...
- 简单动态规划——最长公共子序列&&最长回文子序列&&最长上升||下降子序列
最长公共子序列,顾名思义当然是求两个字符串的最长公共子序列啦,当然,这只是一道非常菜的动规,所以直接附上代码: #include<iostream> #include<cstdio& ...
- NOIP2016提高组初赛(2)四、读程序写结果3、求最长回文子序列
#include <iostream> using namespace std; int lps(string seq, int i, int j) { int len1, len2; i ...
- 最长回文子序列---DP
问题描述 给定一个字符串s,找到其中最长的回文子序列.可以假设s的最大长度为1000. 解题思路 1.说明 首先要弄清楚回文子串和回文子序列的区别,如果一个字符串是"bbbab", ...
- HDU 4632 Palindrome subsequence(区间DP求回文子序列数)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4632 题目大意:给你若干个字符串,回答每个字符串有多少个回文子序列(可以不连续的子串).解题思路: 设 ...
- codevs 2185 最长公共上升子序列--nm的一维求法
2185 最长公共上升子序列 时间限制: 1 s 空间限制: 32000 KB 题目等级 : 钻石 Diamond 题目描述 Description 熊大妈的奶牛在小沐沐的熏陶下开始研究信息题目 ...
- 【24题】P2766最长不下降子序列问题
网络流二十四题 网络流是个好东西,希望我也会. 网络流?\(orz\ zsy!!!!!\) P2766 最长不下降子序列问题 考虑我们是如何\(dp\)这个\(LIS\)的. 我们是倒着推,设置\(d ...
- JDOJ 1946 求最长不下降子序列个数
Description 设有一个整数的序列:b1,b2,…,bn,对于下标i1<i2<…<im,若有bi1≤bi2≤…≤bim 则称存在一个长度为m的不下降序列. 现在有n个数,请你 ...
- [**P2766** 最长不下降子序列问题](https://www.luogu.org/problemnew/show/P2766)
P2766 最长不下降子序列问题 考虑我们是如何\(dp\)这个\(LIS\)的. 我们是倒着推,设置\(dp(i)\)代表以\(i\)为起点的\(LIS\)是多少.转移太显然了 \[ dp(i)=m ...
随机推荐
- js去重的es6做法和es5做法
1.es5做法var array=[1,3,4,5,2,3,4,5,5,5];var ob={};var result=[];array.forEach(function (a) { var key= ...
- Task6.PyTorch理解更多神经网络优化方法
1.了解不同优化器 2.书写优化器代码3.Momentum4.二维优化,随机梯度下降法进行优化实现5.Ada自适应梯度调节法6.RMSProp7.Adam8.PyTorch种优化器选择 梯度下降法: ...
- mysql Update语句 语法
mysql Update语句 语法 作用:用于修改表中的数据.广州大理石机械构件 语法:UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值 mysql Update语句 示例 ...
- JSP实现大文件上传和下载
javaweb上传文件 上传文件的jsp中的部分 上传文件同样可以使用form表单向后端发请求,也可以使用 ajax向后端发请求 1.通过form表单向后端发送请求 <form id=" ...
- codevs 4064 组合 x
很久之前发过啦~不过删掉了...再发一下 4064 组合 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 黄金 Gold 题解 查看运行结果 题目描述 Description 组合就 ...
- SpringBoot整合knife4j
官网说明及用法: 简介 swagger-bootstrap-ui是springfox-swagger的增强UI实现,为Java开发者在使用Swagger的时候,能拥有一份简洁.强大的接口文档体验 核心 ...
- Angular项目 Error: [ngRepeat:dupes] Duplicates in a repeater are not allowed.报错
在angular的项目里,一不小心就会出现这个错误[ngRepeat:dupes] ,这个问题是因为内容有重复引起的解决起来挺简单 在对应的ng-repeat指令中增加track by $index, ...
- ES6 模板语法和分隔符
let user = 'Barret'; console.log(`Hi ${user}!`); // Hi Barret!
- mvn 与 pom.xml
mvn 安装 wget http://mirrors.hust.edu.cn/apache//maven/maven-3/3.0.5/binaries/apache-maven-3.0.5-bin.t ...
- linux 杀掉僵尸进程 (zombie process, defunct)
本文说明为什么会出现僵尸进程 (zombie process, defunct),以及如何杀掉僵尸进程 1. 为什么有僵尸进程 僵尸进程出现在父进程没有回收子进程的 PCB 的时候,这个时候子进程已经 ...