博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
『最小表示法 Necklace』
阅读量:7142 次
发布时间:2019-06-29

本文共 3648 字,大约阅读时间需要 12 分钟。


最小表示法

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

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

\(For\ example:\)

\(S=abcda,S_1=aabcd,S_2=daabc,S_3=cdaab,S_4=bcdaa\)

其中,\(S\)的最小表示为\(S_1\)

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

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

22343424232423223434

Sample Output

Yes2234342423

解析

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

\(Code:\)

#include
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;}


转载于:https://www.cnblogs.com/Parsnip/p/10574375.html

你可能感兴趣的文章
汇编翻转总结及答复(第7周)
查看>>
android自定义view实现公章效果
查看>>
【观察】云栖大会武汉峰会:生态开放是阿里云主旋律
查看>>
docker镜像
查看>>
Extjs MVC开发模式详解
查看>>
MongoDB 创建大量集合测试问题
查看>>
java 删除非空文件夹
查看>>
PHP读取配置文件类(php,ini,yaml,xml)
查看>>
JAAS之快速开发JBOSS自定义认证
查看>>
阿里技术高P访谈之郭东白:与“大象”共舞的技术狂人
查看>>
SVN:服务器资源删掉,本地添加时和删掉的名字同名出现One or more files are in a conflicted state....
查看>>
【原创】RabbitMQ 之 Shovel(翻译)
查看>>
javascript设计模式理论和示例深入分析(下)
查看>>
前端的小玩意(6)——使用padding的左定宽、右自适应布局
查看>>
VMWare 网络连接模式(bridged、NAT、host-only)详解
查看>>
Cannot SET AUTOTRACE 处理办法
查看>>
纯AS3项目导入fl包的方法以及fl.controls.DataGrid的详细应用
查看>>
Android 应用增量升级方案之流程篇
查看>>
Install MongoDB Community Edition on Windows
查看>>
菜鸟学Linux命令:tail命令 查看日志
查看>>