逆序對問題。給一列數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 的資料,這種方法是吃得消的,但是當資料變大時,這種方法就很容易超時,因此要進行優化。這裡講兩種方法,一種是改變統計的演算法,即歸併排序求逆序 另一種是改變儲存的資料結構,...