本文已参与「新人创作礼」活动,一起开启掘金创作之路。
最小表示法
1️⃣ 简介
最小表示法就是找 字符串S的循环同构串中字典序最小的一个 的算法,属于是字符串算法。
循环同构串:
例子:字符串
S:bcad, 则S的循环同构串为bcad,cadb,adbc,dbca故循环同构串可以有多个,它是原字符串循环移位产生的字符串
2️⃣ 实现方法
最小表示法其实就是找到位置i,从这个位置输出S,使得到的同构串字典序最小。
可以参考的链接:
oi-wiki.org/string/mini…
暴力解法
关键是如何找:需要先知道暴力的简单方法,然后再对暴力做一些优化即可。
每次比较的是 和开始的循环同构,把当前比较的位置记为 .
int k = 0, i = 0, j = 1;
while (k < n && i < n && j < n)
{
if (a[(i + k) % n] == a[(j + k) % n])
++k;
else
{
if (sec[(i + k) % n] > sec[(j + k) % n]) ++i;
else ++j;
k = 0;
if (i == j) i++;
}
}
i = min(i, j);
优化后的算法(最小表示法)
优化后的代码:
int i = 0, j = 1, k = 0;
while(i < n and j < n and k < n)
{
if(a[(i + k) % n] == a[(j + k) % n])
k++;
else
{
a[(i + k) % n] > a[(j + k) % n] ? i = i + k + 1 : j = j + k + 1;
if(i == j)
i++;
k = 0;
}
}
i = min(i, j);
模板题目
题目链接
找数组所有的循环同构中最小的字典序的数组
#include<bits/stdc++.h>
using namespace std;
using ll = long long ;
void solve()
{
int n;
cin >> n;
vector<int> a(n + 1);
for(int i = 0; i < n; i++)
cin >> a[i];
int i = 0, j = 1, k = 0;
while(i < n and j < n and k < n)
{
if(a[(i + k) % n] == a[(j + k) % n])
k++;
else
{
a[(i + k) % n] > a[(j + k) % n] ? i = i + k + 1 : j = j + k + 1;
if(i == j)
i++;
k = 0;
}
}
i = min(i, j);
for(int x = 0; x < n; x++)
cout << a[(x + i) % n] << " \n"[x == n - 1];
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
// cin >> t;
t = 1;
while(t--)
solve();
return 0;
}