距离最长的有序对问题

问题描述:

  给定一个无序数组A[0..N-1],求出它的最长子串A[j..k],满足Aj < Ak。


算法0:
  直接枚举j、k,时间复杂度是O(n^2)。


算法1:
  注意到一个性质,对于子串A[i..j..m],如果有Ai <= Aj,那么A[i..j..m]必然优于A[j..m],j就不可能是起始点。所以所求子串的起始点j必然满足Ai > Aj (i < j),以下是求出所有起始点的算法:

head_pos = [0]
min = A[0]
    for i in range(1..N):
        if A[i] < min:
            head_pos.append(i)
     min = A[i]

  可以发现,所求出的起始点数组实际上是以A[0]开始的一个单调递减序列。
   接下来问题就变得简单了,我们只要枚举子串的终止点k,并找出第一个满足A[j] < A[k]的起始点j即可,由于head_pos的单调性,我们可以用二分查找在O(logn)时间内找出j,于是整个算法的复杂度为O(nlogn),辅助空间为O(n)。


算法2:
  首先构造出所有下标值的排序数组P[0..N-1],使得A[P[j]] <= A[P[k]] (j < k),构建算法如下:
    1. 令P[0..N-1] = 0, 1, 2, ..., N-1
    2. 根据S[P[i]]的值对P进行排序

  上面的排序如果使用计数排序的话,构建排序数组的复杂度为O(n)。
  于是问题转变为:在排序数组P中找出(Pi - Pj) 的最大值(i < j 并且 A[Pi] != A[Pj]),这一步也可以在O(n)内解决:

minp = P[0]
minl = 0
for i in range(1..N):
    if P[i] < P[minp]:
        minp = P[i]
    else:
        minl = min(minl, P[i] - minp)

  于是算法总复杂度为O(n),辅助空间O(n)。

posted on 2012-04-14 16:30  RichSelian  阅读(304)  评论(0编辑  收藏  举报

导航