词典上最小的字符串旋转

时间:2018-09-05 17:12:38

标签: algorithm graph-algorithm

有人可以向我解释一下,按字典顺序排列的最小字符串是什么意思。这是来自堆栈交换的示例

  

考虑一个长度为n(1 <= n <= 100000)的字符串。确定其   最小词典旋转。例如,   字符串“ alabala”是:

     

阿拉巴拉

     

labalaa

     

阿巴拉尔

     

巴拉拉

     

alaalab

     

laalaba

     

aalabal

     

其中最小的是“ aalabal”。

所以这说最小的是“ aalabal”,是因为“ aa”在开始时出现两次吗?我无法解释什么使“ aalabal”最小?有人可以提供一些见识吗?

2 个答案:

答案 0 :(得分:0)

由于问题“是什么使“ aalabal”最小?”,答案不可避免:“ lexicographical order”。

答案 1 :(得分:0)

UPD :抱歉,我只是重新阅读了您的问题,看来您被困在词典编纂部分。无论如何,请遵循其他用户提供的一些链接,然后稍后进行检查。

有一种使用Suffix Array(SA)解决此问题的方法。让您的字符串为S,然后将S与自身连接起来,然后应用SA。 SA的输出是一个数组,每个后缀的位置均按字母顺序排序。您可以迭代并查找从[0, |S|)范围内的任何位置开始的第一个后缀。您需要考虑一下为什么会起作用,但是最后您可以很容易地弄清楚。

例如,让S = alabala。您可以在下图中看到alabalaalabala的SA输出:

Suffix Array for string alabalaalabala$

位置在[0, |S|) = [0, 7)范围内的第一个后缀是SA[i] = 6,对应于后缀aalabala

有时在应用SA(实现详细信息)之前在字符串的末尾添加特殊字符很方便。

您可以检查以下在O(Nlg ^ 2N)中运行的SA的简短实现,实现速度更快,但是我想这个SA背后的想法是最简单的。

  1. 编译(g++ sa.cpp
  2. 运行
  3. 使用以下值作为输入:N = 15, S = alabalaalabala$
  4. 然后检查输出。

源代码

#include <iostream>
#include <algorithm>

using namespace std;

const int
      MaxN = 200005;

int N;
int i, k;
char s[MaxN];
int ord[MaxN];
int pos[MaxN];
int buc[MaxN];

bool cmp(const int& a, const int& b) {
    if (pos[a] != pos[b])
        return pos[a] < pos[b];
    if (a + k < N && b + k < N)
        return pos[a + k] < pos[b + k];
    return a > b;
}

int main() {

    cin >> N;
    cin >> s;

    for (i = 0; i < N; i++) {
        ord[i] = i;
        pos[i] = s[i];
    }

    for (k = 0; k < N; k = k ? 2 * k : 1) {
        sort(ord, ord + N, cmp);
        for (i = 1; i < N; i++)
            buc[i] = buc[i-1] + cmp(ord[i-1], ord[i]);
        for (i = 0; i < N; i++)
            pos[ord[i]] = buc[i];
    }

    for (i = 0; i < N; i++)
        cout << ord[i] << " - " << (s + ord[i]) << endl;

    return 0;
}