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

字符字串指的是字符串中连续的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. Python重写父类方法__len__

    class Liar(list): def __len__(self): return super().__len__() + 3 # 直接写 super().__len__() 而没有 return ...

  2. java 8 接口默认方法

    解决问题:在java8 之前的版本,在修改已有的接口的时候,需要修改实现该接口的实现类. 作用:解决接口的修改与现有的实现不兼容的问题.在不影响原有实现类的结构下修改新的功能方法 案例: 首先定义一个 ...

  3. [USACO10HOL]牛的政治Cow Politics

    农夫约翰的奶牛住在N ( <= N <= ,)片不同的草地上,标号为1到N.恰好有N-1条单位长度的双向道路,用各种各样的方法连接这些草地.而且从每片草地出发都可以抵达其他所有草地.也就是 ...

  4. 【bzoj1336/1337/2823】最小圆覆盖

    题目描述: 给出平面上N个点,请求出一个半径最小的圆覆盖住所有的点 输入: 第一行给出数字N,现在N行,每行两个实数x,y表示其坐标. 输出: 输出最小半径,输出保留三位小数. 样例输入: 4 1 0 ...

  5. maven入门问题解决

    记录入门使用maven的问题和解决方法: 一.用mvn clean compile编译报错/ 或者在IDE中编译时,Problem视图显示错误:无法从maven服务器或者私有服务器或者某个网站中中下载 ...

  6. 前端学习记录 week 1

    前端学习记录 week 1 基础知识 CSS盒模型 所有HTML元素可以看作盒子,在CSS中,"box model"这一术语是用来设计和布局时使用.CSS盒模型本质上是一个盒子,封 ...

  7. Taylor Swift -《Fearless》

    最近网上都搜不到Taylor的歌了,分享一张love best的album给大家,支持霉霉的还是去买正版把~ 专辑曲目: 01. “Jump Then Fall” 03:5702. “Untoucha ...

  8. fedora18 You might need to install dependency packages for libxcb.

    22 down vote The page Qt for X11 Requirements lists some packages required to build Qt on Debian. Th ...

  9. picker组件 label组件讲解

    label组件:包住表单的组件,将里面的表单和label里的元素,紧紧的包在一起,当触发label里的元素,就相当于触发了表单组件 属性:for:类型 字符串 表单的 id 的值 picker组件:是 ...

  10. Python编程:从入门到实践—函数

    从函数中修改列表 一家为用户提交的设计制作3D打印模型的公司,需要打印的设计存储在一个列表中,打印后移到另一个列表中. #!/usr/bin/env python # -*- coding:utf-8 ...