最小表示法
今天 LJ 课上讲了最小表示法。感觉很好理解。
决定写一篇博客,自己梳理一下。
最小表示法是
\[\texttt{对于一个字符串S,求其循环同构字符串中S'中字典序最小的一个}
\]
我们可以定义三个指针 \(i,j,k\) 。
其中 \(i=0,j=1,k=0\) ,\(k\) 表示以 \(S_i\) 开头的字符串和以 \(S_j\) 开头的字符串的前 \(k\) 个字符相同。
然后我们枚举 \(k\) 。
当 \(S_{i+k}=S_{j+k}\) 则继续。
当 \(S_{i+k}>S_{j+k}\) 则表明 \(S_{[i,i+k]}\) 肯定不可以作为目标字符串的开头。
当 \(S_{i+k}<S_{j+k}\) 则同理。
当 \(i=j\) 时,令 \(j+1\) 。
后面三种情况都要使 \(k\) 归 \(0\) 。
代码很好写
#include<bits/stdc++.h>
#define FOR(i,j,k) for(int i=(j);i<=(k);i++)
using namespace std;
int n;
int a[300005];
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
inline int Min()
{
int i=0,j=1,k=0;
while(i<n&&j<n&&k<n)
{
int t=a[(i+k)%n]-a[(j+k)%n];
if(!t) k++;
else
{
if(a[(i+k)%n]>a[(j+k)%n]) i+=k+1;
else j+=k+1;
if(i==j) j++;
k=0;
}
}
return min(i,j);
}
int main()
{
n=read();
for(int i=0;i<n;i++) a[i]=read();
int ans=Min();
for(int i=0;i<n;i++)
printf("%d ",a[(i+ans)%n]);
return 0;
}
当然他也可以用来判断两个字符串不计顺序是否本质相同。详细可以参见这个PPT

浙公网安备 33010602011771号