计算数组中的逆序数(inversion)个数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计算数组中的逆序数(inversion)个数相关的知识,希望对你有一定的参考价值。

  今天继续学了算法,首先是一个计算数组中的逆序数的算法。

  通常,很容易想到的计算办法就是运用两个for循环遍历比较整个数组,当某个数字的下标较大,而值却小于小标比它小的某个位置上的值时,逆序数+1,但是此种算法复杂度较高,随着输入数据规模的增大效率会快速下降(即输入的数组变大了),具体的复杂度计算方法如下:设数组有n个元素,则需要遍历n次,而每一次遍历中要与下标在后面的进行比较,在当次遍历中,其后具有(n-当次遍历的元素的下标)个元素,那么就需要进行n^2/2次操作(后面的元素不需要再与前面的比较),运用notation,最后复杂度应该表示为O(n^2),所依此算法的效率就随n的增大而快速降低。所以呢?我们提出一个问题:Can we do better?

  Of course we can, there is always another way.怎么解决呢?其中一个方法是用merge算法。(具体是什么自行研究吧我也还在学习中,简单的说就是把数组分成相等的两部分,如果是奇数就一边多了一个,另一半少一个,然后就不断递归,分别把两部分等分成更小的相等部分,最后分到一定小后排好序,分别找出两部分中分别含有的逆序数(两个数都在一个部分中),还有就是“构成逆序数”的两个数字分别在两部分中),接下来的重点就是找出第二种“逆序数”(我的意思是构成逆序数的第二种方式,就是两个数在不同的两个部分),而merge算法解决这个就很有优势,理由如下:比如员数组是[ 1, 3, 5, 2, 4, 6],分成两部分后排好序分别为A[1 , 3, 5], B[ 2, 4, 6],最终的输出结果为D[1, 2, 3, 4, 5, 6],那么作如下图:(相同数字上下连线,连线交点数即为结果)

1  3  5 , 2   4   6

1  2  3     4   5   6

为什么呢?由A,B生成D的过程就是merge过程,merge通过

i=0, j = 0;

for k=0 to n:

  if A[i] < B[j]:

    D[k] = A[i];

    i++;

  else if A[i] > B[j]:

    D[k] = B[j];

    j++;

这个过程生成最后的D,由此很容易看出,如果在A未被完全转移到D之前,B中的某个元素先被移到了D中,那么当B中这个元素移动时,A中还剩余有多少个元素未移到D的,A中就有多少个元素比这个B中的元素大。综上,交点数即“那种逆序数”。

以上是关于计算数组中的逆序数(inversion)个数的主要内容,如果未能解决你的问题,请参考以下文章

SGU180 Inversions(树状数组求逆序数)

HDU 4911 Inversion 树状数组求逆序数对

逆序对 inversion

HDU - 1394 Minimum Inversion Number(线段树求逆序数---点修改)

UVA 11990 ”Dynamic“ Inversion(线段树+树状数组)

HDU 6318 Swaps and Inversions 思路很巧妙!!!(转换为树状数组或者归并求解逆序数)