逆序對問題

2021-07-12 04:25:26 字數 1656 閱讀 8648

逆序對問題。給一列數a1

,a2,

…,an

,求它的逆序對數,即有多少個有序對(i

,j) ,使得

i<

j 但ai

>aj

。n 可以高達106

由於

n 的數量級到了106

,所以採用o(

n2) 及以上的時間複雜度肯定會超時,所以必須選取o(

nlog

2n) 及以下時間複雜度的演算法。

逆序對的求解思路和歸併排序很像,嘗試寫出

分治三部曲:

劃分問題:將原序列分解成盡可能長度相等的兩個子串行

遞迴過程:統計左子串行和右子串行的逆序對

合併問題:統計左右子串行合併後的逆序對

可以看出和歸併排序的演算法思想差不多,那麼,它們之間的關係是什麼呢?

每當左右子串行合併的時候,可以發現如果右子串行的元素

i 放入臨時容器中,那麼左子串行中當前元素

j到末尾的元素全部都是大於

i 的,由此就可以得到ans+= center - lef + 1這樣的乙個表示式。

#include 

using

namespace

std;

// 求解逆序對

// 分治法

// 劃分問題:把序列分成元素個數盡量相等的兩半

// 遞迴求解:求解兩邊的逆序對

// 合併問題:合併成乙個序列時的逆序對

int ans = 0;

void merges(int *a, int lef, int righ)

// 取中值

int center = lef + (righ - lef) / 2;

// 遞迴左半

merges(a, lef, center);

// 遞迴右半

merges(a, center + 1, righ);

// 合併左半和右半

// 該大小為左半右半大小之和

int totalsize = righ - lef + 1;

int tmp[totalsize];

int n = lef;

int m = center + 1;

int i = 0;

// 左半右半其一不為空

while(n <= center || m <= righ) else

}n = lef;

// 將臨時陣列的值放入原陣列

for(int i = 0; i < totalsize; i++)

}void mergesort(int *a, int n)

int main() ;

int n = 12;

ans = 0;

mergesort(a, n);

cout

<< "逆序對為:"

<< ans << endl;

return

0;}

逆序對為:19

process returned 0 (0x0) execution time : 0.131 s

press any key to continue.

逆序對問題 O nlgn

問題描述 在陣列arr中,i j 如果 arr i arr j 那麼就存在乙個逆序對 目的就是求出逆序對的數目。演算法 暴力求解,o n 2 下面運用了一種很巧妙的方法,通過歸併排序的歸併過程,進行逆序對的統計!具體例子分析 比如 1 5 3 2 4 當 1 3 5 與 2 4 合併的時候,a.1 ...

逆序對問題 O nlgn

問題描述 在陣列arr中,i j 如果 arr i arr j 那麼就存在乙個逆序對 目的就是求出逆序對的數目。演算法 暴力求解,o n 2 下面運用了一種很巧妙的方法,通過歸併排序的歸併過程,進行逆序對的統計!具體例子分析 比如 1 5 3 2 4 當 1 3 5 與 2 4 合併的時候,a.1 ...

序列逆序對問題詳解

知道了逆序對的概念,那麼在程式中可以很容易地用列舉法暴力求出逆序對,時間複雜度為o n2 o n 2 對於n 104 n 104 的資料,這種方法是吃得消的,但是當資料變大時,這種方法就很容易超時,因此要進行優化。這裡講兩種方法,一種是改變統計的演算法,即歸併排序求逆序 另一種是改變儲存的資料結構,...