最小表示法

用途

給一個首尾相連的字符串,找一個位置,從這個位置日後造成一個字符串,使字符串的字典序最小ios

算法

定義三個指針\(i=0\),\(j=1\),\(k=0\)\(i\)\(j\)是當前判斷的位置,\(k\)是相同的串的長度,表示\(str[i...i+k]\)\(str[j...j+k]\)相同。
\(str[i+k]==str[j+k]\)時,顯然,\(k++\)
\(str[i+k] > str[j+k]\)時,發現\(i+k\)位置的字典序要比\(j+k\)位置的字典序大,顯然,\(str[j...j+k]\)的比\(str[i...i+k]\)的更優,字典序更小,那\(i\)位置就不能作開頭了,必需要日後走,這時\(i=i+k+1\)
\(str[i+k] < str[j+k]\)\(j=j+k+1\)
很顯然的是\(i\)不能等於\(j\),因此當\(i==j\)時,\(j(或i)++\)
最後\(i\)\(j\)中較小的那一個就是要找的字符串開始的位置c++

模板

工藝git

/*
最小表示法 
*/
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n, m;
int a[N];
template<class T>inline void read(T &x) {
    x = 0; int f = 0; char ch = getchar();
    while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
    while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
    x = f ? -x : x;
    return ;
}

int Min() {
    int i = 0, j = 1, k = 0;
    while (i < n && j < n && k < n) {
        if (a[(i + k) % n] == a[(j + k) % n]) k++;              //相等k日後移
        else {
            if (a[(i + k) % n] > a[(j + k) % n]) i += k + 1;    //如上文,i的字典序比j的大
            else j += k + 1;                                    //i的字典序比j的小
            if (i == j) j++;                                    //i不能等於j
            k = 0;                                              //k置0
        }
    }
    return min(i, j);
}

int main() {
    read(n);
    for (int i = 0; i < n; ++i) read(a[i]);
    int ans = Min();
    for (int i = 0; i < n; ++i) printf("%d ", a[(i + ans) % n]);
    return 0;
}

poj1509 Glass Beads算法

/*
最小表示法 
*/
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N = 1e5 + 10;
int t, n;
char s[N];

int Min() {
    int i = 0, j = 1, k = 0;
    while (i < n && j < n && k < n) {
        if (s[(i + k) % n] == s[(j + k) % n]) k++;
        else {
            if (s[(i + k) % n] > s[(j + k) % n]) i += k + 1;
            else j += k + 1;
            if (i == j) j++;
            k = 0;
        }
    }
    return min(i, j);
}

int main() {
    cin >> t;
    while (t--) {
        memset(s, 0, sizeof(s));
        cin >> s;
        n = strlen(s);
        printf("%d\n", Min() + 1);
    }       
    return 0;
}

簡單小證實

爲何是\(i=i+k+1\)呢,咱們任取區間\([1,k]\)之間的一個數\(k'\),由於\(str[i+k]>str[j+k]\),因此\(k'\)不論取何值,咱們發現\(str[j+k'...j+k]\)老是比\(str[i+k'...i+k]\)優,因此\(i+k'\)不能作開頭,由於\(k'\)能夠取到\(k\),因此\(i+k\)不能作開頭,因此\(i=i+k+1\)spa

相關文章
相關標籤/搜索