循环数组的最小表示

问题描述

假设有数组a[n],可通过旋转得到n种表示,求字典序最小的表示。

最小表示的典型应用是判断同构问题,例如判断两个字符串是否为变形词,只需将各个串转成最小表示,再判断最小表示是否相同即可。

具体实现

直观做法是枚举所有表示,取字典序最小的,但时间复杂度较高,这里介绍个线性做法。

以字符串为例,下面代码求的是变形词的最小表示,循环数组的求法完全一样。

#include <bits/stdc++.h>
using namespace std;
int MinExp(string s, int len) {
    int i = 0, j = 1, k = 0;
    while (i < len && j < len && k < len) {
        int t = s[(i+k)%len] - s[(j+k)%len];
        if (t == 0) {
            k += 1;
        } else {
            if (t > 0) {
                i += k + 1;
            } else {
                j += k + 1;
            }
            if (i == j) j += 1;
            k = 0;
        }
    }
    return min(i, j);
}
string Print(string s, int len, int start) {
    string ret;
    for (int i = start, j = 0; j < len; j++, i = (i+1) % len)
        ret += s[i];
    return ret;
}
int main() {
    string s;
    while (cin >> s) {
        int start = MinExp(s, s.length());
        cout << Print(s, s.length(), start) << endl;
    }
    return 0;
}
Table of Contents