字符子串和字符子序列的区别

字符字串指的是字符串中连续的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,马拉车)的更多相关文章

  1. hdu6537 /// DP 最长不降子序列->最长公共子序列

    题目大意: 给定一个字符串 字符为0~9 求翻转某个区间后使得串中的最长不降子序列最长 因为字符范围为0~9 假设有一个 0 1 2 3 4 5 6 7 8 9 的序列 此时翻转某个区间得到形如 0 ...

  2. 简单动态规划——最长公共子序列&&最长回文子序列&&最长上升||下降子序列

    最长公共子序列,顾名思义当然是求两个字符串的最长公共子序列啦,当然,这只是一道非常菜的动规,所以直接附上代码: #include<iostream> #include<cstdio& ...

  3. NOIP2016提高组初赛(2)四、读程序写结果3、求最长回文子序列

    #include <iostream> using namespace std; int lps(string seq, int i, int j) { int len1, len2; i ...

  4. 最长回文子序列---DP

    问题描述 给定一个字符串s,找到其中最长的回文子序列.可以假设s的最大长度为1000. 解题思路 1.说明 首先要弄清楚回文子串和回文子序列的区别,如果一个字符串是"bbbab", ...

  5. HDU 4632 Palindrome subsequence(区间DP求回文子序列数)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4632 题目大意:给你若干个字符串,回答每个字符串有多少个回文子序列(可以不连续的子串).解题思路: 设 ...

  6. codevs 2185 最长公共上升子序列--nm的一维求法

    2185 最长公共上升子序列  时间限制: 1 s  空间限制: 32000 KB  题目等级 : 钻石 Diamond 题目描述 Description 熊大妈的奶牛在小沐沐的熏陶下开始研究信息题目 ...

  7. 【24题】P2766最长不下降子序列问题

    网络流二十四题 网络流是个好东西,希望我也会. 网络流?\(orz\ zsy!!!!!\) P2766 最长不下降子序列问题 考虑我们是如何\(dp\)这个\(LIS\)的. 我们是倒着推,设置\(d ...

  8. JDOJ 1946 求最长不下降子序列个数

    Description 设有一个整数的序列:b1,b2,…,bn,对于下标i1<i2<…<im,若有bi1≤bi2≤…≤bim 则称存在一个长度为m的不下降序列. 现在有n个数,请你 ...

  9. [**P2766** 最长不下降子序列问题](https://www.luogu.org/problemnew/show/P2766)

    P2766 最长不下降子序列问题 考虑我们是如何\(dp\)这个\(LIS\)的. 我们是倒着推,设置\(dp(i)\)代表以\(i\)为起点的\(LIS\)是多少.转移太显然了 \[ dp(i)=m ...

随机推荐

  1. unittest-mock-from-import

    https://stackoverflow.com/questions/11351382/mock-patching-from-import-statement-in-python

  2. 与Swing的初见

    ---------------------------参考菜鸟教程的swing课程学习-------------------- Swing 是一个为Java设计的GUI工具包. Swing是JAVA基 ...

  3. js 文件下载 兼容ie

    前置条件:后台接口返回二进制流文件 一.设置前端请求的的 responseType: 'blob' 二.接收请求数据并调用下载 var content = res.data // 接口返回的二进制流v ...

  4. 第七周作业—N42-虚怀若谷

    一.简述OSI七层模型和TCP/IP五层模型 1. OSI七层模型 物理层:二进制传输,为启动.维护以及关闭物理链路定义了电气规范.机械规范.过程规范和功能规范:实际的最终信号的传输是通过物理层实现的 ...

  5. linux运维、架构之路-Kubernetes本地镜像仓库+dashboard部署

    一.部署docker registry            生产环境中我们一般通过搭建本地的私有镜像仓库(docker registry)来拉取镜像. 1.拉取registry镜像 [root@k8 ...

  6. 阿里云产品家族再添新丁:视觉AI、CPFS一体机助力企业全面上云

    近日举行的2019阿里云广东峰会上,阿里云宣布推出面向混合云场景的CPFS一体机和视觉AI一体机,两款新品具备超高性能.开箱即用等特性,极大降低企业上云的周期和门槛. 加上此前推出的POLARDB数据 ...

  7. apiCloud通过ajax获取数据

    <!doctype html> <html> <head> <meta charset="utf-8"> <meta name ...

  8. 修改select的默认样式

    在我们用select的时候,通常因为他的默认样式比较丑而用自己样式,那首先要去掉他的默认样式 去掉select的边框和点击时的蓝色边框 select{border: none;outline: non ...

  9. Spring Cloud Commons教程(三)忽略网络接口

    有时,忽略某些命名网络接口是有用的,因此可以将其从服务发现注册中排除(例如,在Docker容器中运行).可以设置正则表达式的列表,这将导致所需的网络接口被忽略.以下配置将忽略“docker0”接口和以 ...

  10. Spark Streaming的优化之路—从Receiver到Direct模式

    作者:个推数据研发工程师 学长     1 业务背景   随着大数据的快速发展,业务场景越来越复杂,离线式的批处理框架MapReduce已经不能满足业务,大量的场景需要实时的数据处理结果来进行分析.决 ...