阿里巴巴一道笔试题目(待更加细致的修正)
今天阿里笔试题的倒数第二道,给数组排序,这个数组的特点是任一元素现在的位置和把数组排好序后它的位置距离小于k,即a[i]元素在数组排序后将位于{i-k,i+k}这个区间内。要求时间复杂度小于o(nk)。
某人的分析:
因为交换范围不可能超过(i-k,i+k),所以每排完一轮2K,2K中的前K个就是已排好的,不会再动了,这时候可以直接偏移掉
比O(nlogn)和O(nk)小的,只剩下O(nlogk),O(n),O(logn),O(1)这几种情况了,排序算法基本不可能后两种,O(n)的排序都有庞大的空间开销或者特殊的数据范围(比如字节组),所以这种有个参数k的题,根据经验也是O(nlogk)。
方法1:
建一个k的小堆,每次取最小,插入下一个,维护这个堆n次,总共为O(nlogk)。
归纳法证明:
1 前k个取出最小的必然就是全部数组的最小的,因为第一个位置的在[0, k-1]之中的一个。
2 第j个取出来的数字,在数组就在j的位置上。因为根据题意,第j个大的必然在(j-k, j+k)之间。他必然在[0, j+k-1]中第j个大的,前面已经有[0, j-1]了,所以从堆中取出来就是第j个大的。即在数组的第j个位置上。
方法2:
a[i]在排序后的位置是[i-k, i+k],a[i+2k]在排序后的位置是[i+k, i+3k],必然有a[i] <= a[i+2k],所以数组a里实际上有2k个各自有序的、交错的子序列,如a1={a[0], a[2k], a[4k]…},a2={a[1], a[2k+1], a[4k+1], …}
所以可以用2k-路归并排序,用一个大小为2k的小顶堆辅助归并,时间复杂度是O(n*log2k)