solution:
首先對這個問題可以採用任意一種排序演算法,例如使用歸併排序可以在o(nlog(n))的時間內完成。
題目中給出每個元素在排完序後和原來的位置相差不超過k,即其實就說明了這個陣列其實對某些元素來說其實已經相對有序了,比如考慮兩個元素 a[0]和 a[k+1],那麼一定有a[2k+1] >= a[0],如若不然的話,必定需要交換a[2k+1]和a[0]兩個元素,這樣二者肯定會有乙個元素距原來的位置大於k。
下面就根據上面的這個規律來進行對演算法進行優化。
假設現有乙個陣列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及其以後的元素中
無序陣列 的特殊排序
分析 對於一般陣列的排序顯然 o n 是無法完成的。既然題目這樣要求,肯定原先的陣列有一定的規律,讓人們去尋找一種機會。例如 原始陣列 a 10,6,9,5,2,8,4,7,1,3 如果把它們從小到大排序且應該是 b 1,2,3,4,5,6,7,8,9,10 也就是說 如果我們觀察 a b 的對映關...
codeup 問題 B 特殊排序
題目描述 輸入一系列整數,將其中最大的數挑出,並將剩下的數進行排序。輸入 輸入第一行包括1個整數n,1 n 1000,代表輸入資料的個數。接下來的一行有n個整數。輸出 可能有多組測試資料,對於每組資料,第一行輸出乙個整數,代表n個整數中的最大值,並將此值從陣列中去除,將剩下的數進行排序。第二行將排序...
陣列的排序問題。
程式的版權和版本宣告部分 檔名稱 array.cpp 作 者 董萬鵬 完成日期 2012 年12月2 日 版本號 v1.0 輸入描述 無 問題描述 冒泡法排列陣列 include using namespace std void bubble sort int x,int num void outp...