题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
解题思路
算法
归并排序,在“并”的时候求逆序对
思路
本体要统计的是逆序对的个数,我们在归并排序过程中,对合并的两部分分别统计逆序对个数,然后再统计两个部分之间的逆序对个数,把他们 +=,就可以得到我们的结果
过程
在归并的过程中,将数组分为左和右两部分,根据归并排序的定义,两部分区间为:
- 左:
[l, mid] - 右:
[mid + 1, r]
我们要求逆序对,实际上就是求左,右两部分分别有多少个逆序对,以及左右跨区间之间有多少个逆序对,因此结果是对 3 部分统计的加和,我们用 ans 来统计
接下来,我们来看一个区间怎么来进行统计
我们统计的过程发生在合并时,右区间当前指针指向的是相对小值时发生,例如:
[1,3(p1),4], [2(p2), 2, 3]
p1, p2 指针分别指向左右区间元素,当两指针指向为上述情况时,可见在左区间右 mid - p1 + 1 个元素大于 p2 指向的元素,我们在移动 p2 之后,进行统计
代码
/**
* @param {number[]} nums
* @return {number}
*/
var reversePairs = function (nums) {
return countResult(nums, 0, nums.length - 1)
}
function countResult(nums, l, r) {
// if the section length <= 1, reverse pairs number is 0
if (l >= r) return 0
let ans = 0
const mid = (l + r) >> 1,
temp = []
// pairs in the left section
ans += countResult(nums, l, mid)
// pairs in the right section
ans += countResult(nums, mid + 1, r)
// pairs across the left & right
let k = l,
p1 = l,
p2 = mid + 1
while (p1 <= mid || p2 <= r) {
if (p2 > r || (p1 <= mid && nums[p1] <= nums[p2])) {
temp[k++] = nums[p1++]
} else {
temp[k++] = nums[p2++]
ans += mid - p1 + 1
}
}
for (let i = l; i <= r; i++) {
nums[i] = temp[i]
}
return ans
}