逆序對問題算是很經典了,最簡單的暴力破解時間複雜度o(n2),時間複雜度大於o(n2)的演算法是非常糟糕了,所以我們採用歸併排序的演算法改動一下,即可獲得o(nlogn)的演算法。
逆序對定義:數列中如果 i < j && arr[i] > arr[j],則arr[i]和arr[j]為一對逆序對。
// 逆序對個數
private
static
long ropcount =0;
/** * 計算逆序對
* * @param arr
* @param left
* @param right
*/public
static
void
calcrop
(int
arr,
int left,
int right)
/** * 一次計算
* * @param arr
* @param left
* @param mid
* @param right
*/public
static
void
calc
(int
arr,
int left,
int mid,
int right)
}
正確性測試有那麼幾組資料
資料逆序對的數量
2032331
000分別跑起來,結果都對的上,暫未發現結果不符的資料。
壓力測試
跑一百萬條資料,看看用時。
int
arr =
newint
[1000
*1000];
for(
int i =
0; i < arr.length; i++
)long start = system.
currenttimemillis()
;calcrop
(arr,
0, arr.length -1)
;system.out.
println
(ropcount)
;long end = system.
currenttimemillis()
;system.out.
println
("一百萬條資料用時:"
+(end-start)
/1000
+"s"
);
害!可能是我自己寫的一次歸併演算法不好,一百萬條資料竟然要用一分鐘。。。
我又改了改,上面那個一次歸併的演算法使用時間換空間,一直是在arr中操作,需要不斷的搬動元素,所以耗時巨大。
改進的思路是空間換時間,使用乙個輔助陣列和原陣列相同,使用大小個入隊的方法來進行一次歸併。
改進後的一次歸併計算的方法如下:
/**
* 一次計算
* * @param arr
* @param left
* @param mid
* @param right
*/public
static
void
calc
(int
arr,
int left,
int mid,
int right)
else
}// 後半部分沒搬完
if(i > mid && j <= right)
// 前半部分沒搬完
if(i <= mid && j > right)
system.
arraycopy
(helper,
0, arr, left, helper.length)
;}
再用百萬條資料測試一下:
看吧,速度有了質的提公升,所以在硬體發達的時代,不要吝嗇而用時間換空間,適當的使用輔助空間會使演算法速度大幅度提公升。
就是這樣哈哈,拜了個拜!
普及練習場 分治演算法 逆序對
題目鏈結 看到這個資料量,你就不應該想著去寫個暴力。我原來已經寫過一遍這個題目了,並且還記得是歸併排序來做,但是有點記不得是怎麼推導出思路的了,因此決定重新推導一遍。我找到了原來的ppt,並且加一點自己的理解吧。一開始的時候應該是1 2 但是1 被分解成更小的1 和更小的2 當只有兩個數的時候,就只...
演算法之逆序對
假設a 1.n 是乙個有n個不同數的陣列。若ia j 則對偶 i,j 稱為a的乙個逆序對 inversion 列出陣列的5個逆序對 由集合中的元素構成的什麼陣列具有最多的逆序對?它有多少逆序對?插入排序的執行時間與輸入陣列中的逆序對的數量有什麼關係?給出乙個求在n個元素的任何排列中逆序對數量的演算法...
演算法篇 逆序對
設 a 為乙個有 n 個數字的有序集 n 1 其中所有數字各不相同。如果存在正整數 i,j使得 1 i j n 而且 a i a j 則 這個有序對稱為 a 的乙個逆序對,也稱作逆序數。排序的過程就是消除逆序對的過程。逆序對越多,相對來說排序所需要的時間就越多。列舉陣列元素的所有組合,對於 長度為 ...