使用后缀数组进行最小字典旋转

时间:2012-06-30 20:38:58

标签: algorithm suffix-array

    Consider a string of length n (1 <= n <= 100000). 
    Determine its minimum lexicographic rotation. 
    For example, the rotations of the string “alabala” are:

    alabala

    labalaa

    abalaal

    balaala

    alaalab

    laalaba

    aalabal

    and the smallest among them is “aalabal”.

这是来自ACM ICPC 2003的问题。其他一些用户已经在堆栈流中提出了这个问题。[但这没用,因为我想通过后缀Array来做。]

如何使用后缀数组来解决这个问题?

直到现在我做了什么?

(1)假设给定的字符串是S.

我将字符串S连接到自身以获得字符串S'。

即。 S'= S + S

(2)。然后我在O(nlog n)时间内找到了S'的后缀数组。

For example:
    S=alabala
    S'=alabalaalabala

Suffix No. Index    Suffixes

0       13      a
1       6       aalabala
2       9       abala
3       2       abalaalabala
4       11      ala
5       4       alaalabala
6       7       alabala
7       0       alabalaalabala
8       10      bala
9       3       balaalabala
10      12      la
11      5       laalabala
12      8       labala
13      1       labalaalabala

所以我计算了后缀数组SA,SA [] = {13,6,9,2,11,4,7,0,10,3,12,5,8,1}。

我还计算了每个后缀的LCPs b / w [虽然我不相信我会在这个问题中要求它。]

现在如何进一步继续。如何使用SA获得理想的结果?

使用非常小的示例进行说明将非常有效

谢谢!

3 个答案:

答案 0 :(得分:2)

看来你应该在SA中取第一个后缀,哪个索引介于0和长度(S)-1之间。

一些解释:S的所有旋转都位于S'后缀的开头,位于0和长度(S)之间的位置 - 1.后缀数组以字典顺序保留后缀,因此您只需要选择从第一个开始的后缀S的轮换。

答案 1 :(得分:2)

如果你使用O(n log n)算法(按首字母排序,然后按前两个字母排序,然后按前四个,......),你可以做一点修改后缀数组。

不要对字符串的后缀进行排序,而是循环旋转。它应该是算法中的小修改。那么你将直接获得所需的结果。

如果你仍想使用你的方法,那么只需要取0到N之间的第一个索引。

答案 2 :(得分:0)

全部谢谢。对于大多数测试用例,vkorchagin和usamec的回答都是正确的,但它们不适用于以下测试用例(S =“baabaa”)

S = baabaa; S'= baabaabaabaa;

Suffix| Suffix  |  Suffixes
Index | Length  |

11      1       a
10      2       aa
7       5       aabaa
4       8       aabaabaa
1       11      aabaabaabaa
8       4       abaa
5       7       abaabaa
2       10      abaabaabaa
9       3       baa
6       6       baabaa
3       9       baabaabaa
0       12      baabaabaabaa

取索引在0到S.length() - 1 之间的第一个后缀对上述测试用例不起作用。如果我这样做,那么结果是4,但是正确答案是1。

所以我稍微修改了答案。

这是我为上述答案添加/修改额外条件的原因::

(1)我选了索引在0到S.length() - 1之间的第一个后缀。

让我们说它的索引是:= ExpectedIdx。

在上面的例子中,ExpectedIdx = 4。

(2)。现在,ExpectedIdx可能是也可能不是答案。原因是后缀数组中的下一个后缀可能会产生相同的答案。

示例::

采用起始索引为4(ExpectedIdx),aabaab aa。的后缀,我们得到aabaab作为最小Lexograhic旋转字符串。

采用下一个后缀,aabaab aabaa。

我们还得到aabaab作为最小Lexograhic旋转字符串。

但是前一个需要移位4而后一个需要移位1. 所以正确答案是1而不是4。

所以我使用了最长公共前缀(LCP)的概念来检查相似性,最后得到了接受。http://livearchive.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=756

编辑::这是伪代码 -

int ExpectedIdx,ExpectedSuffixNumber,ExpectedSuffixLength;
for(int i=0;i<strlen(str);++i)//str = Length of S'
{
    suffixsize=strlen(str)-SA[i];
    if(suffixsize>(Len/2))//Len/2:=Size of S
    {
        ExpectedIdx=SA[i];
        ExpectedSuffixNumber=i;
        ExpectedSuffixLength=suffixsize;
        break;
    }
}
//Now this ExpectediDx may or may not be the correct answer.

int finalans=ExpectedIdx;//Lets assume initially that ExpectedIdx is a correct/final answer.
for(int i=(ExpectedSuffixNumber+1);i<Len;++i)//Check the Next Suffix 
{
    if(LCP[i]>Len/2)//LCP[i]=Lingest common prefix of adjacent prefixes in a suffix Array.
    {
        if(SA[i]>finalans)
        {
            finalans=SA[i];
        }
    }
    else
        break;
}