题目的思路很巧妙,是通过归并排序的特殊性质来实现低时间复杂度的逆序数对查找。精髓在于归并排序过程中,会把左右两部分都已经排好序的数组进行合并,而这个合并的过程,就可以确定逆序对的数量并进行累加。
index : [0, 1, 2, 3, 4, 5, 6]
element : [4, 7, 9][1, 2, 6, 8]
array : [...a...][....b.....]
pointers: [i] [j]
merged : [1, 2, 4]
以上面这个情况为例,我们已经把 1, 2, 4 三个元素合并好了,然后我们看 i 指向的元素 7 和 j 指向的元素 6。
如果我们在数组 b 中找到了比数组 a 还小的数字,我们就发现了逆序对。总共有几个逆序对呢?数组 a 里还剩几个数,就有几个。也就是 [..., 7, ... , 6, ...] 和 [..., 9, ..., 6, ...] 。我们不需要管中间出现了多少别的数,在这次迭代中能找到就累加即可。
代码如下:
const reversePairs = (nums) => {
// array for temp value storage
const tmp = Array(nums.length).fill(null);
const mergeSort = (left, right) => {
// end condition
if (left >= right) {
return 0;
}
const mid = Math.floor((left + right) / 2);
// recursively sort
let res = mergeSort(left, mid) + mergeSort(mid + 1, right);
// fill up current interval with numbers already sorted in last call
for (let k = left; k <= right; k++) {
tmp[k] = nums[k];
}
let i = left;
let j = mid + 1;
for (let k = left; k <= right; k++) {
if (i > mid) {
// if all items in the left array is added,
// fill in the rest with items in the right array
nums[k] = tmp[j];
j++;
} else if (j > right) {
// if all items in the right array is added,
// fill in the rest with items in the left array
nums[k] = tmp[i];
i++;
} else {
if (tmp[i] <= tmp[j]) {
// current left item is less or equal than current right item,
// which is sorted so just merge
nums[k] = tmp[i];
i++;
} else {
// current left item is greater than current right item,
// where reversed pairs need to be counted
nums[k] = tmp[j];
j++;
res += mid - i + 1;
}
}
}
return res;
}
return mergeSort(0, nums.length - 1);
};