逆序对
逆序对计算
1 归并排序
归并排序天然就可统计逆序对,在归并时有以下两种方式统计:
当左侧当前指针指向位置的数字CUR较小时,本轮将其加入归并后的数组,注意到右数组当前指针左边的都是小于CUR的,但是他们位置却在其右侧,所以逆序对贡献为l2-old_l2
1 | if (a <= b) { // 这里包含等于 可以用全1数组模拟想想 |
当右侧当前指针指向位置的数字CUR较小时,本轮将其加入归并后的数组,注意到左数组当前指针及其右边都是大于CUR的,但是他们的位置却在其左侧,所以逆序对的贡献为old_l2 - l1
1 | if (a <= b) // 这里包含等于 可以用全1数组模拟想想 |
下面是完整代码
1 | class Solution { |
2 离散化+树状数组
树状数组可以非常方便进行区间统计和单点修改,对于原数组,我们从后往前遍历,依次将其加入树状数组(计数),并求其左侧(小于的)之前的所有已插入的数字的和,最终即可求得总的逆序对。然而,原数组的数值范围波动较大,不能直接用树状数组去记录,其间必有许多0表现出极大的稀疏性,因此需要对原数组进行离散化。所谓离散化,即将原数组映射到1~N的数据范围,让数据的范围全部聚集在一起,减少空间浪费,有利于树状数组发挥。因为在该问题中我们不关心数据的绝对大小,仅关心数据的相对大小,所以可以离散化。离散化需要借助偏向的二分查找进行。
对于数组[1,3,2,4,1],离散化后的结果是1,4,3,5,1,程序处理过程中树状数组的变化为(树状数组0位弃用):
1 | 对于原数组 [1,4,3,5,1] |
1 | // 树状数组 |
小记
- 已知的树状数组的两种用途
- 原数组的下标作为索引,进行区间统计和修改
- 原数组的值作为下标,进行区间计数(本题)