『最小表示法 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+n−1),S′(j,j+n−1)
2.(1) 如果扫描了n个字符两个串仍然相等,则说明这个字符串只由一个字符构成,任意位置开头都是最小表示
2.(2) 找到位置S′i+k!=S′j+k,若S′i+k>S′j+k,则说明位置j更优,更新位置i=i+k+1,若S′i+k<S′j+k,则说明位置i更优,更新位置j=j+k+1
3.若i>n,则说明位置j为最小表示,若j>n,则说明位置i为最小表示
为什么S′i+k>S′j+k时,直接将i更新为i+k+1呢,相信这是最大的一个疑问。
Explain:
当S′i+k>S′j+k时,显然S′i不是最小表示,因为存在一个更优的最小表示S′j。然而,S′i+p(1≤p≤k)均不是最小表示,对于任意的一个S′i+p,一定也存在一个S′j+p比它更优,因为它们不断向后比较,同样会在i+k处发现有S′i+k>S′j+k。这样就说明了当一个i在i+k的位置发现不优时,i+k以前的也均不优,直接将i更新为i+k+1即可。
同理,发现j不优时也是一样的。
Code:
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#
2234342423
2423223434
Sample Output#
Yes
2234342423
解析#
这就是一道最小表示法模板题,直接将两个串分别转为最小表示法,再比较是否相同即可。如果相同,直接将最小表示法输出。
Code:
#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;
}
<后记>
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· dotnet 源代码生成器分析器入门
· ASP.NET Core 模型验证消息的本地化新姿势
· 对象命名为何需要避免'-er'和'-or'后缀
· SQL Server如何跟踪自动统计信息更新?
· AI与.NET技术实操系列:使用Catalyst进行自然语言处理
· 官方的 MCP C# SDK:csharp-sdk
· 一款 .NET 开源、功能强大的远程连接管理工具,支持 RDP、VNC、SSH 等多种主流协议!
· 提示词工程师自白:我如何用一个技巧解放自己的生产力
· 一文搞懂MCP协议与Function Call的区别
· 如何不购买域名在云服务器上搭建HTTPS服务