Processing math: 100%

『最小表示法 Necklace』

Parsnip·2019-03-21 20:32·318 次阅读

『最小表示法 Necklace』

<更新提示>

<第一次更新>


<正文>

最小表示法#

这是一个简单的字符串算法,其解决的问题如下:

给定一个字符串S,长度为n,如果把它的最后一个字符不断放到最前面,会得到n个不同的字符串,那么我们称这n个字符串是循环同构的。这n个字符串中字典序最小的一个,我们就称为S的最小表示。

For example:

S=abcda,S1=aabcd,S2=daabc,S3=cdaab,S4=bcdaa

其中,S的最小表示为S1

了解了概念以后,我们将介绍一种算法,可以在O(n)的时间内求出一个字符串的最小表示。

对于一个环,最朴素的方法就是复制一倍接在原序列后面,这里我们就要用到这种方法:令字符串$$S'i=\begin{cases}1 \leq i\leq n ,S_i\n<i \leq 2n ,S\end{cases}$$

然后,利用两个指针i,j扫描字符串S,其具体方法如下:

1.初始化i=1,j=2
2.直接向后扫描,比较两个循环同构串S(i,i+n1),S(j,j+n1)
2.(1) 如果扫描了n个字符两个串仍然相等,则说明这个字符串只由一个字符构成,任意位置开头都是最小表示
2.(2) 找到位置Si+k!=Sj+k,若Si+k>Sj+k,则说明位置j更优,更新位置i=i+k+1,若Si+k<Sj+k,则说明位置i更优,更新位置j=j+k+1
3.若i>n,则说明位置j为最小表示,若j>n,则说明位置i为最小表示

为什么Si+k>Sj+k时,直接将i更新为i+k+1呢,相信这是最大的一个疑问。

Explain:

Si+k>Sj+k时,显然Si不是最小表示,因为存在一个更优的最小表示Sj。然而,Si+p(1pk)均不是最小表示,对于任意的一个Si+p,一定也存在一个Sj+p比它更优,因为它们不断向后比较,同样会在i+k处发现有Si+k>Sj+k。这样就说明了当一个ii+k的位置发现不优时,i+k以前的也均不优,直接将i更新为i+k+1即可。

同理,发现j不优时也是一样的。

Code:

Copy
inline void solve(void) { int ans; int i=1,j=2,k; while(i<=n&&j<=n) { for(k=0;k<=n&&s[i+k]==s[j+k];k++); if(k==n)break; if(a[i+k]>a[j+k]) { i=i+k+1; if(i==j)i++; } else { j=j+k+1; if(i==j)j++; } } ans=min(i,j); }

Necklace#

Description#

有一天,袁同学绵了一条价值连城宝石项链,但是,一个严重的问题是,他竟然忘记了项链的主人是谁!在得知此事后,很多人向袁同学发来了很多邮件,都说项链是自己的,要求他归还(显然其中最多只有一个人说了真话)。袁同学要求每个人都写了一段关于自己项链的描述: 项链上的宝石用数字0至9来标示。一个对于项链的表示就是从项链的某个宝石开始,顺指针绕一圈,沿途记下经过的宝石,比如如下项链: 1-2-3-4   

它的可能的四种表示是0123、1230、2301、3012。

袁☆同学现在心急如焚,于是他找到了你,希望你能够编一个程序,判断两个给定的描述是否代表同一个项链(注意,项链是不会翻转的)。

给定两个项链的表示,判断他们是否可能是一条项链。

Input Format#

输入文件只有两行,每行一个由0至9组成的字符串,描述一个项链的表示(保证项链的长度是相等的)。

Output Format#

如果两条项链不可能同构,那么输出’No’,否则的话,第一行输出一个’Yes’

第二行输出该项链的字典序最小的表示。 设L = 项链长度,L <= 1000000。

Sample Input#

Copy
2234342423 2423223434

Sample Output#

Copy
Yes 2234342423

解析#

这就是一道最小表示法模板题,直接将两个串分别转为最小表示法,再比较是否相同即可。如果相同,直接将最小表示法输出。

Code:

Copy
#include<bits/stdc++.h> using namespace std; const int N=1000000+20; int lena,lenb; char a[N*2],b[N*2],Mina[N],Minb[N]; inline void input(void) { scanf("%s",a+1); scanf("%s",b+1); lena=strlen(a+1); lenb=strlen(b+1); for(int i=1;i<=lena;i++) a[lena+i]=a[i]; for(int i=1;i<=lenb;i++) b[lenb+i]=b[i]; } inline void solvea(void) { int ans; int i=1,j=2,k; while(i<=lena&&j<=lena) { for(k=0;k<=lena&&a[i+k]==a[j+k];k++); if(k==lena)break; if(a[i+k]>a[j+k]) { i=i+k+1; if(i==j)i++; } else { j=j+k+1; if(i==j)j++; } } ans=min(i,j); for(int p=1;p<=lena;p++) Mina[p]=a[ans+p-1]; } inline void solveb(void) { int ans; int i=1,j=2,k; while(i<=lenb&&j<=lenb) { for(k=0;k<=lenb&&b[i+k]==b[j+k];k++); if(k==lenb)break; if(b[i+k]>b[j+k]) { i=i+k+1; if(i==j)i++; } else { j=j+k+1; if(i==j)j++; } } ans=min(i,j); for(int p=1;p<=lenb;p++) Minb[p]=b[ans+p-1]; } int main() { input(); solvea(); solveb(); int flag=1; if(lena!=lenb) { printf("No\n"); return 0; } for(int i=1;i<=lena;i++) if(Mina[i]^Minb[i])flag=0; if(!flag) { printf("No\n"); return 0; } else { printf("Yes\n"); for(int i=1;i<=lena;i++) printf("%c",Mina[i]); puts(""); } return 0; }

<后记>

posted @   Parsnip  阅读(318)  评论(0编辑  收藏  举报
编辑推荐:
· dotnet 源代码生成器分析器入门
· ASP.NET Core 模型验证消息的本地化新姿势
· 对象命名为何需要避免'-er'和'-or'后缀
· SQL Server如何跟踪自动统计信息更新?
· AI与.NET技术实操系列:使用Catalyst进行自然语言处理
阅读排行:
· 官方的 MCP C# SDK:csharp-sdk
· 一款 .NET 开源、功能强大的远程连接管理工具,支持 RDP、VNC、SSH 等多种主流协议!
· 提示词工程师自白:我如何用一个技巧解放自己的生产力
· 一文搞懂MCP协议与Function Call的区别
· 如何不购买域名在云服务器上搭建HTTPS服务
点击右上角即可分享
微信分享提示
目录