[230523 剑指51] 数组中的逆序对
一 题目
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:
输入: [7,5,6,4]
输出: 5
限制:
0 <= 数组长度 <= 50000
二 整体思路
整体思路是使用归并排序的算法。在归并排序的合并过程中,若右边子数组指针指向的元素小于左边子数组指针指向的元素,则意味着出现了逆序对,逆序对数量为左子数组中未合并的元素数量。
三 关键点/重点/难点
重难点在递归实现归并排序。
易错点在合并过程中 if 分支需要先判断下标合法性以防止越界。
四 代码分析
class Solution {
public:
int reversePairs(vector<int>& nums) {
vector<int> tmp(nums.size());
return mergeSort(0, nums.size() - 1, nums, tmp);
}
private:
//返回nums中的逆序对数
int mergeSort(int left, int right, vector<int>& nums, vector<int>& tmp) {
if(left >= right) {
return 0;
}
int mid = left + (right - left) / 2;
int result = mergeSort(left, mid, nums, tmp) + mergeSort(mid + 1, right, nums, tmp);
//merge操作
//使用tmp记录merge前的数组,巧思:tmp引用传参,可以在各层递归中重复使用,节省内存
for(int i = left; i <= right; ++i) {
tmp[i] = nums[i];
}
int i = left, j = mid + 1;
for(int k = left; k <= right; ++k) {
//在if分支中优先判断下标是否合法,防止越界
if(i == mid + 1) {
nums[k] = tmp[j++];
} else if(j == right + 1 || tmp[i] <= tmp[j]) {
nums[k] = tmp[i++];
} else {
nums[k] = tmp[j++];
result += mid - i + 1;
}
}
return result;
}
};
(五)一题多解
🕧be lazy.
(六) 知识扩展
别的就不说了,就是觉得这个归并排序里面的 tmp 数组引用传参写得非常妙啊!重复使用,节约空间,good.