2021年02月12日 周五 天气晴 【不悲叹过去,不荒废现在,不惧怕未来】
1. 问题简介
2. 归并排序的应用
这道题的本质是考察归并排序,逆序对可以在归并排序的过程中一并算出。
主要注意两点,都是关于加快代码运行速度的:
(1)临时数组tmp开辟为全局数组,可以提高运行速度;
(2)剪枝:归并排序为升序的前提下,如果左右都已排好序,而且左边的最大值 <= 右边的最小值,那么 [l,r]
天然升序,并且不存在跨越左边和右边的逆序对,可以提前返回。
class Solution {
public:
int ans = 0;
// 开辟为全局数组,可以提高运行速度
vector<int> tmp;
int reversePairs(vector<int>& nums) {
int n = nums.size();
if(n<2) return 0;
tmp.resize(n);
mergeSort(nums,0,n-1);
return ans;
}
void mergeSort(vector<int>& nums, int l, int r){
if(l < r){
int m = l + (r - l)/2;
// 计算左边的逆序对
mergeSort(nums,l,m);
// 计算右边的逆序对
mergeSort(nums,m+1,r);
// 剪枝:归并排序为升序的前提下,如果左右都已排好序,而且左边的最大值 <= 右边的最小值,
// 那么[l,r]天然升序,并且不存在跨越左边和右边的逆序对,可以提前返回
if(nums[m]<=nums[m+1]) return;
// 计算跨越左边和右边的逆序对
merge(nums,l,m,r);
}
}
void merge(vector<int>& nums, int l, int m, int r){
int i = l, j = m+1, idx = l;
while(i<=m && j<=r){
if(nums[i]<=nums[j]){
tmp[idx++] = nums[i++];
}
else{
// 计算逆序对
ans += m - i + 1;
tmp[idx++] = nums[j++];
}
}
while (i <= m)
tmp[idx++] = nums[i++];
while (j <= r)
tmp[idx++] = nums[j++];
for(int k=l;k<=r;++k){
nums[k] = tmp[k];
}
}
};
参考文献
《剑指offer 第二版》
https://www.cnblogs.com/chengxiao/p/6194356.html
https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof/solution/zi-jie-ti-ku-jian-51-kun-nan-shu-zu-zhon-eipc/