字符串最小表示初探 By cellur925
我们考虑有一个字符串,可以从这个字符串的不同位置出发,把这个字符串大声朗读出来,当到字符串末端的时候再从头开始读,直到回到“梦开始的地方”。
设字符串长度为\(n\),那么有\(n\)种不同的读法。我们现在想要在这些读法中找一个字符串使得他字典序最小,如何快速求出?
我们当然可以用其他朴素的方法(这里不再赘述),但其实我们有更高效的线性算法:最小表示法。
算法描述
首先把这个字符串复制二倍接在后面(类似断环为链)
然后利用两个指针\(i=1\)和\(j=2\)在\(k=0\)的帮助下向后扫,当遇到\(i+k\)和\(j+k\)位置的字符不相等时,就退出。
如果\(i+k\)位置更大一些,直接把\(i\)跳到\(i+k+1\)。因为可以证明从\(i+1\)到\(i+k\)都不是字符串的最小表示,扫这部分就是冗余的。
两个指针不断尝试向后移动,一个移动到结尾就停止扫描,保证复杂度在\(O(n)\)内。
void work()
{
n=strlen(str+1);ans=0;
for(int i=1;i<=n;i++) str[n+i]=str[i];
int i=1,j=2,k;
while(i<=n&&j<=n)
{
for(k=0;k<=n&&str[i+k]==str[j+k];k++);
if(k>=n) break;
if(str[i+k]>str[j+k])
{i=i+k+1;if(i==j) i++;}
else
{j=j+k+1;if(i==j) j++;}
}
ans=min(i,j);
printf("%d\n",ans);
}
两道新鲜热乎的例题
例1:bzoj1398寻找主人
给你两个字符串,问你他们是否同构,若同构输出最小表示。
第二问是裸题,第一问我们只要分别求出两个字符串的最小表示看他们是否相同即可。
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
bool flag;
int pos1,pos2,len;
char s1[3000000],s2[3000000];
void work1()
{
len=strlen(s1+1);
for(int i=1;i<=len;i++) s1[i+len]=s1[i];
int i=1,j=2,k;
while(i<=len&&j<=len)
{
for(k=0;k<=len&&s1[i+k]==s1[j+k];k++);
if(k>=len) break;
if(s1[i+k]>s1[j+k])
{
i=i+k+1;
if(i==j) i++;
}
else
{
j=j+k+1;
if(i==j) j++;
}
}
pos1=min(i,j);
}
void work2()
{
for(int i=1;i<=len;i++) s2[i+len]=s2[i];
int i=1,j=2,k;
while(i<=len&&j<=len)
{
for(k=0;k<=len&&s2[i+k]==s2[j+k];k++);
if(k>=len) break;
if(s2[i+k]>s2[j+k])
{
i=i+k+1;
if(i==j) i++;
}
else
{
j=j+k+1;
if(i==j) j++;
}
}
pos2=min(i,j);
}
int main()
{
scanf("%s",s1+1);
scanf("%s",s2+1);
work1();work2();
int i=pos1,j=pos2,cnt=1;
while(cnt<=len)
{
if(s1[i]==s2[j]) i++,j++,cnt++;
else {flag=1;break;}
}
if(flag)
{
printf("No\n");
return 0;
}
else printf("Yes\n");
cnt=1;i=pos1;
while(cnt<=len) cout<<s1[i],i++,cnt++;
return 0;
}
例2 poj1509
给你很多字符串,求出他们最小表示的起点位置。
真·裸题。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,Q,ans;
char str[30000];
void work()
{
n=strlen(str+1);ans=0;
for(int i=1;i<=n;i++) str[n+i]=str[i];
int i=1,j=2,k;
while(i<=n&&j<=n)
{
for(k=0;k<=n&&str[i+k]==str[j+k];k++);
if(k>=n) break;
if(str[i+k]>str[j+k])
{i=i+k+1;if(i==j) i++;}
else
{j=j+k+1;if(i==j) j++;}
}
ans=min(i,j);
printf("%d\n",ans);
}
int main()
{
scanf("%d",&Q);
while(Q--)
{
scanf("%s",str+1);
work();
}
return 0;
}
感觉这种算法可扩展性不太强(?),不过当个暴力工具就好了\(qwq\)。
字符串最小表示初探 By cellur925的更多相关文章
- hdu 4333"Revolving Digits"(KMP求字符串最小循环节+拓展KMP)
传送门 题意: 此题意很好理解,便不在此赘述: 题解: 解题思路:KMP求字符串最小循环节+拓展KMP ①首先,根据KMP求字符串最小循环节的算法求出字符串s的最小循环节的长度,记为 k: ②根据拓展 ...
- 牛客练习赛36 A Rabbit的字符串(字符串最小表示法)
链接:https://ac.nowcoder.com/acm/contest/328/A来源:牛客网 题目描述 Rabbit得到了一个字符串,她的好朋友xxx可以给这个字符串施加一次魔法. 魔法可以选 ...
- bzoj2176 Strange string(字符串最小表示法)
Time Limit: 10 Sec Memory Limit: 259 MB 给定一个字符串S = {S1, S2, S3 … Sn}, 如果在串SS中, 子串T(|T| = n)为所有长度为n的 ...
- [coj 1353 Guessing the Number]kmp,字符串最小表示法
题意:给一个字符串,求它的最小子串,使得原串是通过它重复得到的字符串的一个子串. 思路:先求最小长度,最小循环长度可以利用kmp的next数组快速得到,求出长度后然后利用字符串最小表示法求循环节的最小 ...
- 字符串最小表示法 O(n)算法
网上看了这篇文章后还是感觉有些地方讲的没有详细的证明所以添加了一点 红色字是博主写的 求字符串的循环最小表示: 上面说的两个字符串同构的,并没有直接先求出Min(s),而是通过指针移动,当某次匹配串长 ...
- KMP求字符串最小循环节
证明1: 对于一个字符串S,长度为L,如果由长度为len的字符串s(字符串s的最小循环节是其本身)循环k次构成,那么字符串s就是字符串S的最小循环节 那么字符串有个很重要的性质和KMP挂钩,即 i ...
- POJ--2406Power Strings+KMP求字符串最小周期
题目链接:点击进入 事实上就是KMP算法next数组的简单应用.假设我们设这个字符串的最小周期为x 长度为len,那么由next数组的意义,我们知道len-next[len]的值就会等于x.这就是这个 ...
- EditDistance,求两个字符串最小编辑距离,动态规划
问题描述: 题目描述Edit DistanceGiven two words word1 and word2, find the minimum number of steps required to ...
- BZOJ1398: Vijos1382寻找主人 Necklace 字符串最小表示法
Description 给定两个项链的表示,判断他们是否可能是一条项链. Input 输入文件只有两行,每行一个由0至9组成的字符串,描述一个项链的表示(保证项链的长度是相等的). Output 如果 ...
随机推荐
- POJO对象建立规则
1.所有POJO类属性必须使用包装数据类型,RPC方法的返回值和参数必须使用包装数据类型. 说明:POJO类属性没有初值是提醒使用者在使用时,必须自己显示的进行赋值,任何NPE问题,或者入库检查,都由 ...
- swift-ios开发pod的使用(1)
MAC安裝CocoaPods http://www.cnblogs.com/surge/p/4436360.html 请注意我的环境,这个很重要 xcode版本7.3.2 mac 版本OS X ...
- SpringMVC ajax技术无刷新文件上传下载删除示例
参考 Spring MVC中上传文件实例 SpringMVC结合ajaxfileupload.js实现ajax无刷新文件上传 Spring MVC 文件上传下载 (FileOperateUtil.ja ...
- HackerRank leonardo-and-lucky-numbers —— 模线性方程的通解
题目链接:https://vjudge.net/problem/HackerRank-leonardo-and-lucky-numbers 题解: 1.根据扩展欧几里得:7*x + 4*y = gcd ...
- VS2010关于调用ffmpeg借口出错
win7 下开发视频服务器,用到ffmpeg,debug版本运行正常,切换到release时,出现"0x00905a4d 处未处理的异常: 0xC0000005: 读取位置 0x00905a ...
- 为 Android 平台开发一个输入法
学习目标: 实现新的输入法 学习目的: 掌握Android输入法框架 学习收获: Android 1.5 新特色之一就是输入法框架(Input Method Framework,IMF),正是它的出现 ...
- Update 出现在的问题
报错提示:之前的操作没有完成,运行deanup被打断,请先执行Cleanup方法. 正常右键点击Cleanup,如果只让默认值勾选,可能还是会报这个错.所以正确操作如下: 全部选中再点击OK,这样就可 ...
- pytest用例setup和teardown
函数式以下两种: setup_function/teardown_function 每个用例开始和结束调用一次 setup_module/teardown_module setup_modu ...
- VMware桥接模式选择宿主机物理网卡
当宿主机有多块物理网卡时,VMware桥接模式也要根据情况选择使用的物理网卡. 比如宿主机有两块物理网卡,一个连外网,一个连内网,如果想与内网组成局域网就需要选择宿主机的内网网卡,反之选择外网网卡,当 ...
- 二、myeclipse中配置mybatis中xml的自动提示
以mybatis中mapper.xml为例 方法一: 步骤一:在mybatis-3.3.0.jar包中寻找mybatis-3-mapper.dtd文件. 可以用360压缩打开mybatis-3.3.0 ...