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获得理想的结果?
使用非常小的示例进行说明将非常有效。
谢谢!
答案 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;
}