距离最长的有序对问题
问题描述:
给定一个无序数组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) 编辑 收藏 举报