最长回文子序列/最长回文子串(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 ...
随机推荐
- MongoDB的特殊操作
相比关系型数据库, Array [1,2,3,4,5] 和 Object { 'name':'DragonFire' } 是MongoDB 比较特殊的类型了 特殊在哪里呢?在他们的操作上又有什么需要注 ...
- 【UOJ#400】暴力写挂
题目链接 题意 两棵树 , 求出下面式子的最大值. \[dep[u]+dep[v]-dep[LCA(u,v)]-dep'[LCA'(u,v)]\] Sol 边分治. 与第一棵树有关的信息比较多,所以对 ...
- 初识Django之前端后端与数据库的配置
目录 一.静态文件配置 二.关于form表单的补充 三.post请求出现403问题 四.request方法初识 4.1判断当前请求方式 4.2request.POST与request.GET 五.py ...
- 完美解决linux不能编辑sshd_cofig和实现xshell远程连接的问题
第一步:我们使用命令行vim /etc/ssh/sshd_config 执行修改,强制保持 :wq! 系统不让我们修改这个文件 "/etc/ssh/sshd_config" ...
- [springboot jpa] [bug] Could not open JPA EntityManager for transaction
前言 最近,测试环境遇到了一个问题.经过一番百度加谷歌,终于解决了这个问题.写下这篇博客是为了记录下解决过程,以便以后查看.也希望可以帮助更多的人. 环境 java版本:8 框架:spring clo ...
- 浅谈IPv4至IPv6演进的实施路径
作者:个推运维平台网络工程师 宗堂 1 业务背景 在互联网呈现爆炸式发展的今天, IPv4网络地址数量匮乏等问题将会影响到我国的互联网发展与应用,制约物联网.5G等新业务开展.今年4月国家工信部发 ...
- RTP/RTSP编程
https://blog.csdn.net/pu1030/article/details/7619908 http://blog.chinaunix.net/uid-27875-id-5017161. ...
- Hadoop 服务SYS CPU过高导致宕机问题
最近某hadoop集群多次出现机器宕机,现象为瞬间机器的sys cpu增长至100%,机器无法登录.只能硬件重启,ganglia cpu信息如下: 首先怀疑有用户启动了比较奇葩的job,导致不合理的系 ...
- iOS环境搭建
Xcode安装 一定要在App Store上下载XCode . git config常用配置 设置lg命令 查看分支图 git config --global alias.lg "log - ...
- ASP.NET Core 上传微信永久视频素材
话不多说直接上源码 请求实体 public class AddVideoRequest { /// <summary> /// 文件流 / ...