String 对长度为n的n个字符串进行排序的最快方法是什么?

String 对长度为n的n个字符串进行排序的最快方法是什么?,string,algorithm,sorting,String,Algorithm,Sorting,我有n根弦,每根长度为n。我想把它们按升序排列 我能想到的最好的算法是n^2 log n,这是一种快速排序算法。(比较两个字符串需要O(n)个时间)。挑战是在O(n^2)时间内完成。我怎么做 此外,不允许使用基数排序方法,因为您不知道手边字母表中的字母数。在优于O(N^2 Log N)的情况下,不可能解决所有情况。 但是,如果存在可以放松字符串比较的约束,则可以对其进行优化 -如果字符串具有高重复率且来自有限有序集。您可以使用count sort中的想法,并使用地图存储它们的计数。稍后,仅对映射

我有n根弦,每根长度为n。我想把它们按升序排列

我能想到的最好的算法是n^2 log n,这是一种快速排序算法。(比较两个字符串需要O(n)个时间)。挑战是在O(n^2)时间内完成。我怎么做


此外,不允许使用基数排序方法,因为您不知道手边字母表中的字母数。

在优于O(N^2 Log N)的情况下,不可能解决所有情况。 但是,如果存在可以放松字符串比较的约束,则可以对其进行优化

-如果字符串具有高重复率且来自有限有序集。您可以使用count sort中的想法,并使用地图存储它们的计数。稍后,仅对映射键进行排序就足够了。O(NMLogM),其中M是唯一字符串的数量。为此,您甚至可以直接使用TreeMap

-如果字符串不是随机的,而是某个超级字符串的后缀,则可以很好地完成此操作
O(N对数^2N)

假设任何字母都是a到z

由于不需要就地排序,请创建长度为26的链表数组:

List[] sorted= new List[26]; // here each element is a list, where you can append 
对于该字符串中的字母,其排序位置是ascii:x-'a'的差值。 例如,“c”的位置是2,它将被置于位置as

sorted[2].add('c')
这样,只对一个字符串进行排序,取n

因此,对所有字符串进行排序需要n^2

例如,如果您有“zdcbacdca”

排序之后,一个可能的结果如下

0   1  2  3 ...  25  <br/>
a   b  c  d ...  z   <br/>
a   b  c             <br/>
       c
01123。。。25
a b c d。。。z
a b c
C

注意:字母集合的假设决定了排序数组的长度。

这里最简单的方法是使用(n^2)或(kn)


更高级的方法是使用(n log n)。

对于少量字符串,常规比较排序可能比基数排序快,因为基数排序所需的时间与存储每个字符所需的位数成比例。对于2字节Unicode编码,并对相等常数因子做出一些(无可否认是可疑的)假设,只有当log2(n)>16时,即排序超过65000个字符串时,基数排序才会更快

有一件事我还没有提到,就是字符串的比较排序可以通过利用已知的公共前缀来增强。

假设我们的字符串是S[0],S[1],…,S[n-1]。让我们考虑用一个最长的公共前缀(LCP)表来扩充GysErrt。首先,我们不需要在内存中移动整个字符串,而是将索引列表操作到一个固定的字符串表中

每当我们合并字符串索引X[0]、…、X[k-1]和Y[0]、…、Y[k-1]的两个排序列表以生成Z[0]、…、Z[2k-1],我们还将得到两个LCP表(X的LCPX[0]、…、LCPX[k-1]和Y的LCPY[0]、…、LCPY[k-1]),我们还需要生成LCPZ[0]、…、LCPZ[2k-1]。LCPX[i]给出了X[i]的最长前缀的长度,该前缀也是X[i-1]的前缀,对于LCPY和LCPZ也是如此

第一次比较是S[X[0]]和S[Y[0]]之间的比较,不能使用LCP信息,我们需要完整的O(n)字符比较来确定结果。但在那之后,事情就加快了

在第一次比较中,在S[X[0]]和S[Y[0]]之间,我们还可以计算它们的LCP的长度——称为L。将Z[0]设置为S[X[0]]和S[Y[0]]中比较小的一个,并将LCPZ[0]=0。我们将在L中保留最近比较的LCP长度。我们还将在M中记录最后一个“比较失败者”与其块中的下一个字符串共享的LCP的长度:即,如果两个字符串S[X[i]]和S[Y[j]]之间的最新比较确定S[X[i]]更小,则M=LCPX[i+1],否则M=LCPY[j+1]

基本思想是:在任何合并步骤中进行第一次字符串比较之后,S[X[i]]和S[Y[j]]之间的所有剩余字符串比较都可以从最小的L和M开始,而不是从0开始。这是因为我们知道S[X[i]]和S[Y[j]]必须在开始时至少在这么多字符上保持一致,所以我们不需要费心比较它们。随着越来越大的已排序字符串块的形成,块中的相邻字符串将倾向于以更长的公共前缀开头,因此这些LCP值将变得更大,从而消除越来越多无意义的字符比较

在每次比较S[X[i]]和S[Y[j]]之后,“失败者”的字符串索引像往常一样附加到Z。计算相应的LCPZ值很容易:如果最后两个输家都来自X,则取LCPX[i];如果它们都来自Y,则取LCPY[j];如果它们来自不同的块,取前面的值L

事实上,我们可以做得更好。假设上一次比较发现S[X[i]]L,那么我们已经知道S[X[i+1] 我不知道这是否会将复杂性从O(n^2 logn)提高到更好的程度,但它应该会有所帮助。

您可以构建一个,这将花费O(s*n)

详情:

没有这样的限制,所以我想我们可以假设10^4或更大。好的,你可以通过字符串中的N^2个字母来计算字母表中的字母数(只需要O(N^2)时间),然后
0   1  2  3 ...  25  <br/>
a   b  c  d ...  z   <br/>
a   b  c             <br/>
       c