首页 > 其他分享 >【学习笔记】Manacher(马拉车)求回文子串

【学习笔记】Manacher(马拉车)求回文子串

时间:2023-08-24 17:11:46浏览次数:30  
标签:子串 字符 Manacher 矩阵 leq 字符串 回文 样例

点击查看目录

目录

参考资料与图片来源

参考博客

我觉得这个博客讲的不好,他只讲看规律得到的结论,原因却不说,怪。

参考博客2

oi-wiki

算法思路

对于长度可能为奇可能为偶的情况,首先要预处理字符串,在每个字符左右增加一个无关字符 #

\[\begin{aligned} &\text{bob}\\ &\downarrow\\ &\text{#b#o#b#}\\ \\ &\text{moon}\\ &\downarrow\\ &\text{#m#o#o#n#} \end{aligned} \]

这样字符串的长度就固定为奇数了。

接下来我们选定一个字符,以他为中心向左右扩展,求回文半径,如果只有其一个字符,半径为 \(1\)。

如:

\[\begin{aligned} &\text{# 1 # 2 # 2 # 1 # 2 # 2 #}\\ &1\ \ 2\ \ 1\ \ 2\ 5\ \ 2\ \ 1\ \ 6\ 1\ \ 2\ \ 3\ \ 2\ \ 1 \end{aligned} \]

或者:

为什么要求回文半径?

以上面的 \(22122\) 为例子,其中心的 \(1\) 回文半径是 \(6\),而该字符串原本的长度是 \(5\)。

这是一个普遍的规律:\(\left\lceil\frac{\text{原字符串长度}}{2}\right\rceil=\)回文中心左(包括回文中心)的字符串长度(即字符串回文半径)\(=\)回文中心左增加的 # 数。

设字符串回文半径长度为 \(P\),那么加了#的字符串长度就为 \(2\times P-1\),而分隔符是 \(P\) 个,故原字符串长度 \(T=2\times P-1-P=P-1\)

故,字符串回文长度=回文半径长度 \(-1\)。

现在我们就有了字符串长度,而由于第一个和最后一个字符都是#且需要搜索回文,所以为了防止越界,我们在前面加上一个非回文字符%,而后面就不用加了,因为结尾一定有一个字符'/0'

(tips:越界例如:o#b#o#b# 中的位置是 \(3\),但是半径是 \(4\),相减得起点为 \(-1\),越界)

具体实现

最后就是如何求解我们的回文半径数组 \(P\) 的问题。

设 \(mi\) 是 \(i\) 位置之前回文长度能到达最远的右端点的回文串的重心位置,\(R\) 是最大回文串的能达到的右端点的值。

  • 若 \(i\leq R\),我们可以找到 \(i\) 以 \(mi\) 为对称点对称到左边的位置 \(j=2\times mi-i\)。
  1. 若 \(P_j<R-i\),那么证明 \(i\) 的回文没有超出 \(R\) 的边界,\(P_i=P_j\)。

  1. 若 \(P_j\geq R-i\),超出 \(R\) 的部分一个个和前面匹配。

  • 若 \(i>R\),那有什么办法,一一匹配呗。

时间复杂度 \(O(n)\)。

有代码:

Miku's Code
string Manacher(string s){
    string res="$#";
    for(int i=0;i<s.size();++i){
        res+=s[i];
        res+="#";
    } 
	/*改造字符串*/
	/*数组*/
    vector<int> P;
    for(rg i=0;i<=res.size();++i)	P.push_back(0);
    int mi=0,right=0;   		//mi为最大回文串对应的中心点,right为该回文串能达到的最右端的值
    int maxLen=0,maxPoint=0;    //maxLen为最大回文串的长度,maxPoint为记录中心点
    for(int i=1;i<res.size();++i){
    	if(right>i)	P[i]=min(P[2*mi-i],right-i);
		else	P[i]=1; 
        while(res[i+P[i]]==res[i-P[i]])	++P[i];
        if(right<i+P[i]){
		//超过之前的最右端,则改变中心点和对应的最右端
            right=i+P[i];
            mi=i;
    	}
        if(maxLen<P[i]){
		//更新最大回文串的长度,并记下此时的点
            maxLen=P[i];
            maxPoint=i;
        }
    }
    return s.substr((maxPoint-maxLen)/2,maxLen-1);
    //在原串中提取最大回文子串 
}

然后将函数返回值改成 int 和 \(maxLen-1\) 就能切掉洛谷的模板题。

洛谷题目链接:模板Manacher

(似乎我过这道题的时候数据过水,但是新的 hack 并没有卡掉咱捏)

例题

Sonya and Matrix Beauty

题目链接

题面翻译

题目描述

一句话题意:给定一个 \(n \times m\) 的字符矩阵,请求出有多少个子矩阵在重排子矩阵每一行的字符后,使得子矩阵的每行每列都是回文串。

Sonya 最近过了生日,她收到一个 \(n \times m\) 的字符矩阵。

我们称一个子矩阵是美丽的,当且仅当在重新排列这个子矩阵每一行的字符后,使得这个子矩阵的每一行每一列都是回文串。

Sonya 想要知道这个矩阵中有几个子矩阵是美丽的。

输入格式

第一行两个整数 \(n,m\),意义如上文所述。

接下来 \(n\) 行一行 \(m\) 个字符,表示这个子矩阵每一行的字符。

输出格式

一行一个整数,表示美丽的子矩阵数目

数据范围

对于 \(1 \leq m,n \leq 250\)

题目描述

Sonya had a birthday recently. She was presented with the matrix of size $ n\times m $ and consist of lowercase Latin letters. We assume that the rows are numbered by integers from $ 1 $ to $ n $ from bottom to top, and the columns are numbered from $ 1 $ to $ m $ from left to right.

Let's call a submatrix $ (i_1, j_1, i_2, j_2) $ $ (1\leq i_1\leq i_2\leq n; 1\leq j_1\leq j_2\leq m) $ elements $ a_{ij} $ of this matrix, such that $ i_1\leq i\leq i_2 $ and $ j_1\leq j\leq j_2 $ . Sonya states that a submatrix is beautiful if we can independently reorder the characters in each row (not in column) so that all rows and columns of this submatrix form palidroms.

Let's recall that a string is called palindrome if it reads the same from left to right and from right to left. For example, strings $ abacaba, bcaacb, a $ are palindromes while strings $ abca, acbba, ab $ are not.

Help Sonya to find the number of beautiful submatrixes. Submatrixes are different if there is an element that belongs to only one submatrix.

输入格式

The first line contains two integers $ n $ and $ m $ $ (1\leq n, m\leq 250) $ — the matrix dimensions.

Each of the next $ n $ lines contains $ m $ lowercase Latin letters.

输出格式

Print one integer — the number of beautiful submatrixes.

样例 #1

样例输入 #1

1 3
aba

样例输出 #1

4

样例 #2

样例输入 #2

2 3
aca
aac

样例输出 #2

11

样例 #3

样例输入 #3

3 5
accac
aaaba
cccaa

样例输出 #3

43

提示

In the first example, the following submatrixes are beautiful: $ ((1, 1), (1, 1)); ((1, 2), (1, 2)); $ $ ((1, 3), (1, 3)); ((1, 1), (1, 3)) $ .

In the second example, all submatrixes that consist of one element and the following are beautiful: $ ((1, 1), (2, 1)); $ $ ((1, 1), (1, 3)); ((2, 1), (2, 3)); ((1, 1), (2, 3)); ((2, 1), (2, 2)) $ .

Some of the beautiful submatrixes are: $ ((1, 1), (1, 5)); ((1, 2), (3, 4)); $ $ ((1, 1), (3, 5)) $ .

The submatrix $ ((1, 1), (3, 5)) $ is beautiful since it can be reordered as:

<br></br>accca<br></br>aabaa<br></br>accca<br></br>In such a matrix every row and every column form palindromes.

解题

睡个觉先,等我睡醒就写

标签:子串,字符,Manacher,矩阵,leq,字符串,回文,样例
From: https://www.cnblogs.com/sonnety-v0cali0d-kksk/p/Manacher_is-not_horse-pull-a-car_written-b

相关文章

  • [刷题笔记] Luogu P2679 [NOIP2015 提高组] 子串
    ProblemDescription我们可以换个思路。从字符串\(A\)中拿出\(k\)个字串使其变成\(B\)。求有几种不同的方案?Analysis我们发现\(A\)中的一个字符取或者不取影响后面的决策,这并不代表它一定有后效性,我们可以记录这一层状态。和最长公共子序列同理,定义\(f_{i,j,k,l}(\fo......
  • 算法学习-Manacher
    什么是ManacherManacher算法可以以\(O(|S|)\)的时间复杂度求出一个字符串的最长回文子串。算法过程令\(k_i\)为以\(i\)为回文中心向右扩展到的最远的位置(即若串\(T_{l\simr}\)回文串,那么\(T\)的回文中心为\(T_{\frac{l+r}{2}}\)),注意到偶数长度的串不具有回文中心......
  • python判断字符串是否包含子串的五种方法
    python判断字符串是否包含子串的五种方法一、用find()方法判断要判断某一个字符串是否包含某一个子串,方法之一是可以利用python内置的字符串方法find()来查找,如果查找到,就返回子串第一个字符在原字符串中的索引位置,如果找不到,则返回-1,实例代码如下:>>>string='笨鸟工具,x1y1z1......
  • Manacher笔记
    Manacher算法应用于一种特定的场景:查找一个长度为\(n\)的字符串\(S\)的最长回文子串,Manacher的复杂度为\(O(n)\),是这种场景中效率最高的算法。首先对字符串\(S\)做一个变换来化简问题,原字符串的“中心字符”可能有一个或者两个。在\(S\)的每个字符左右各插入一个不......
  • YACS 2023年8月月赛 乙组 T1 最长回文 题解
    题目链接小清新的区间DP题。看到数据范围以及回文一眼盯真得到是区间DP。设$f[i][j]$为区间$[i,j]$成为回文串最少要经过几次操作,转移一个个看。首先可以删掉第$j$个,$f[i][j]=\min(f[i][j],f[i][j-1]+1)$,同理也可以删掉第$i$个,$f[i][j]=\min(f[i][j],f[i+1][j]+1)$......
  • [Luogu P8716] 回文日期 题解
    STEP1:分析题目大意:给定一个8位数的日期,请你计算该日期之后下一个回文日期和下一个ABABBABA型的回文日期各是哪一天。这一题一眼看出是P2010的升级版,所以要先考虑到超时问题,因为如果一天一天地枚举,时间复杂度会非常高,所以我们不能直接枚举。因为题目只要"回文",所以我们只......
  • 第11周项目6-回文、素数(4)(5)
    问题及代码:/**Copyright(c)2014,烟台大学计算机学院*Allrightsreserved.*文件名称:MADE44.cpp*作者:孙化龙*完成日期:2014年11月6日*版本号:v1.0**问题描述:多文件组织程序*/#include<iostream>usingnamespacestd;intreverse(intx);boolisPrime......
  • dp-最长回文子序列
    最长回文子序列算法导论3rd-15.2问题描述回文:palindrome,是正序和逆序完全相同的非空字符串一个字符串有许多子序列,可以通过删除某些字符而变成回文字符串,字符串“cabbeaf”,删掉‘c’、'e'、‘f’后剩下的子串“abba”就是回文字符串,也是其中最长的回文子序列。在一个给定的......
  • #yyds干货盘点# LeetCode程序员面试金典:最短回文串
    题目:给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。 示例1:输入:s="aacecaaa"输出:"aaacecaaa"示例2:输入:s="abcd"输出:"dcbabcd"代码实现:classSolution{publicStringshortestPalindrome(Strings){......
  • 回文数列
    #include<iostream>usingnamespacestd;boola(stringn){ if(n[0]==n[n.size()-1]){ if(n.size()<=3){ return1; }else{ n=n.substr(1,n.size()-2); a(n); return1; } }}intmain(intargc,char**argv){ stringn; cin>>n;......