逆序数的分治算法

给我们一个序列, 让我们求其逆序数:

如3 2 1 4

逆序数为: 2+1+0+0=3

 

我们这样定义一个序列的逆序数: 序列a1 a2 a3 a2 ...an

这个序列的逆序数C, 等于a1,a2...的逆序数的和.即 C=sum(Ci)

Ci为满足ai > aj (j > i)的数的总的个数, 即Ci = sum(ai > aj) (j >i).

 

我们一般写的算法一般会做N(N-1)/2次比较, 时间复杂度为: O(N^2).

 

下面采用的分而治之的思想来改进:

假设我们将序列a1 a2 a3 a2 ...an分成两份: B0=(a1 a2 an/2) B1 = (a (n/2+1)...an)

那么C=C(B0)+C(B1)+M(B0B1)

如果我们直接去计算M(B0B1), f(n) = 2*f(n/2)+c*n^2, 计算出来的结果是f(n)=n*f(1) + 2c*n^2 - 2c*n, 那么效率依然是O(N^2), 我们通过什么方式改进呢?

那假如让B0,B1有序就好了! 嗯,对的. 我们在归并排序的过程先将B0,B1排成有序数列,再来求B0′B1′的逆序数, 这时求M(B0′B1′)效率就是O(N).

即,C=C(B0′) + C(B1′) + M(B0′B1′).

下面给出求C(B0′B1′)的代码, 你在下面的完整的求逆序数的算法中也可以找到:


  1. int x, m; //序列B0[x,y], B1[m, n]   
  2. for(i x; <= y; ++i)  
  3.  
  4.     while(j <= && arr[i] arr[j])  
  5.         ++j;  
  6.     nOrder += j-m;  
  7.  
  <
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值