题解:P13270 【模板】最小表示法
最小表示法的概念
最小表示法是一种用于处理字符串循环同构问题的算法。当一个字符串可以通过循环移位得到另一个字符串时,这两个字符串被称为循环同构。例如,字符串 "abc" 的循环同构字符串包括 "abc" 、 "bca" 和 "cab" 。最小表示法就是找到这些循环同构字符串中字典序最小的那个。
前置知识
- 字符串循环移位:将字符串的前
k 个字符移到字符串的末尾,形成新的字符串。 - 字典序:字符串比较的一种方式,按字符的 ASCII 码值逐位比较。
真不是为了水字数。
算法证明
我们需要证明:算法最终返回的起点一定是所有可能起点中字典序最小的。
证明:我们运用反证法。假设存在
但由于
算法的时间复杂度由
思路
那我们该如何去求字符串的最小表示呢?
我们先扩展字符串,相当于把它再复制一遍然后加到原来字符串的后面,这样做是为了便于处理循环移位。
接下来我们初始化指针。令 i = 0 和 j = 1 分别表示两个可能的最小表示的起始位置。
令 k = 0 表示当前比较的长度。
然后比较 s[i + k] 和 s[j + k]:
如果相等,s[i + k] 大于 s[j + k],说明从
最终,
输出从起始位置截取长度为
code
#include <bits/stdc++.h>
using namespace std;
int n;
string s;
int main(){
cin>>n>>s;
s=s+s; // 复制字符串以处理循环移位
int i=0,j=1,k=0;
while(i<n&&j<n&&k<n){//开始处理循环移位
if(s[i+k]==s[j+k]){
k++;
}
else{
if(s[i+k]>s[j+k]){
i=i+k+1;
}
else{
j=j+k+1;
}
if(i==j){
j++;
}
k=0;
}
}
int start=min(i,j);//确定最小表示的起始位置
cout<<s.substr(start,n); //直接输出
return 0;//朴实无华的结尾
}
如果觉得写的好的请点个赞再走呗。
管理大大求过 QAQ 。