特殊的数组排序问题

问题:有一个数组A,将A排序之后,原数组中的每个元素在排序数组中位置相差不超过K. 请设计一个排序算法。


解:

首先对这个问题可以采用任意一种排序算法,例如使用归并排序可以在O(nLog(n))的时间内完成。

题目中给出每个元素在排完序后和原来的位置相差不超过K,即其实就说明了这个数组其实对某些元素来说其实已经相对有序了,比如考虑两个元素 A[0]和 A[k+1],那么一定有A[2k+1] >= A[0],如若不然的话,必定需要交换A[2k+1]和A[0]两个元素,这样二者肯定会有一个元素距原来的位置大于k。

下面就根据上面的这个规律来进行对算法进行优化。暂且将上面的规律定义为#推论1#


假设现有一个数组A[1....2n] 共2n个元素,使用二分排序的方式对左右两半部分分别排序,得到A[1...n]和A[n+1...2n],现在取A[1...n]的后k个元素和A[n+1...2n]的前K个元素,即A[1...n-k,n-k+1...n]和A[n+1...n+k,n+k+1...2n],根据推论1可以知道A[1...n-k]<= A[n+k+1...2n],否则必定会有一个A[n+k+1...2n]中的元素落到A[1...n-k],因为A[n+k+1...2n]中元素的最小原始下标可能为n+1,所以其最小距离着已经变为(n+1)-(n-k)=k+1,与题意相违。 

现在再证明 A[n-k+1...n]中的元素也都小于等于A[n+k+1...2n]中的元素,假设现在有一个元素A[x]( n-k+1<=x<=n) 大于A[n+k+1],那么重新排列后A[n]这个元素的位置一定是在n+k+1这个位置,故其移动的距离不小于K+1了,与题意矛盾。

同理可知A[1...n-k] <= A[n+1..n+k].

所以在合并阶段就需要对A[n-k+1...n]和A[n+1...n+k]这两段进行合并即可。


上面使用二分排序的方法可能会比较复杂,可以证明其时间复杂度为O(N * Log(K))


下面给出一个比较简单的方法:

使用一个大小为K的最小堆,开始将前K个建一个最小堆,然后将最小的取出,然后将第K+1个元素添加到最小堆,然后取第二个最小,然后将第K+2个放入最小堆,...

如此可以使用O(N*log(K))的时间可以排序。

证明为什么可以使用最小堆来做:

1. 首先可以证明最小的一个一定出现在前K个元素中,否则排序之后最小的元素和原来的位置相差一定超过K。

2. 利用1的性质可以知道第二小的元素一定出现在去掉最小元素后的堆和K+1的元素集合中,而不可能出现在第K+2及其以后的元素中

你可能感兴趣的:(算法)