排序第一篇——逆序对

309

这是我参与更文挑战的第7天,活动详情查看:更文挑战

数组的逆序对

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

截屏2021-06-07 下午11.10.56.png

思路分析

最简单的依旧是暴力的思想,两个for循环解决问题,时间复杂度O(N方),空间复杂度O(1)。

不妨仔细看看这个题干,答案永远是隐藏在题干中。逆序对本身就是前面的数字大于后面的数字,所以我们判断的时候会用n方的复杂度求解,那么怎么提高效率呢,就是利用数字的有序性,比方说我知道第一个点后面有6个数字小于第一个点,那么当第二个点大于第一个点时,那么第二个点至少大于6个点。

知道这个有什么用呢?听起来是废话

我不建议去死记硬背上面我这个蹩脚的描述,不过你确实可以将它和归并排序的特点联系起来,上述描述分别暴露了有序,分治两个点。(什么是分治,一步求不出来答案就叫分治,第二个点大于第一个点是过程,有序数组中第二个点和第一个点相邻就是结果)

那么怎么利用归并排序求解逆序对呢?

归并排序无非是分为拆分成小数组,小数组合并成大数组两个过程(当然大多数分治排序都是会这样)。

拆分过程对我们要有序的人来说没有任何价值,但是合并则不然。

合并的过程中,由于数组内部有序,故当arr2[x]<arr1[m]时,arr1从m到最后的节点都大于arr2[x].

因此arr[x]的逆序对至少为arr.size - m个。

以此类推,最终会得到整个数组的逆序个数

结尾说一句

这个建议在两个角度看arr[x],一个是上面的他作为“carry”点,小于前面很多的数,增加了很多个逆序对。 一个是作为“被carry”点,因为自己前面的数,小于后面的一个数,被增加了很多个逆序对(当然这个时候后面的一个数就是carry点了,所以不需要计这部分)