2020.8.18更新
解题思路
参考数组中的逆序对官方题解
此题采用归并排序的思想,分,治(排序),合并——即是本题的重点,合并的时候进行计算
代码
class Solution {
public:
int reversePairs(vector<int>& nums) {
int n = nums.size();
vector<int> tmp(n);
return mergeSort(nums, tmp, 0, n - 1);
}
//归并排序的思想,在合并时,计算逆序对
int mergeSort(vector<int>& nums, vector<int>& tmp, int left, int right) {
if (left >= right) return 0;
int mid = left + (right - left) / 2;
int inv_count = mergeSort(nums, tmp, left, mid) + mergeSort(nums, tmp, mid + 1, right);
//合并
int i = left, j = mid + 1;
for (int k = left; k <= right; k++) {
if (j > right) { tmp[k] = nums[i++]; inv_count += j - (mid + 1); }//如果右边数组中已经取完,而左边没取完时计算贡献
else if (i > mid) { tmp[k] = nums[j++]; }
else if (nums[i] <= nums[j]) { tmp[k] = nums[i++]; inv_count += j - (mid + 1); }//nums[i]<=nums[j]时计算贡献,注意这里要为<=,否则如果两数相等,也会计算贡献
else { tmp[k] = nums[j++]; }
}
for (int k = left; k <= right; k++) {
nums[k] = tmp[k];
}
cout << "inv_count: " << inv_count << endl;
return inv_count;
}
};
解题思路
分治法:
采用的就是归并函数中的分治思想,该题与分治排序的不同点在于,在治的过程中进行逆序对的统计,逆序对的个数为
cnt += center - i + 1;
这也是在归并排序上要加的代码
代码
/*
思路:分治
通过分的方式,获得每个子区间,在合并每个子区间时计算每个子区间内部的逆序对个数
*/
#include<iostream>
#include <vector>
using std::vector;
class Solution {
int cnt = 0;
public:
int reversePairs(vector<int>& nums) {
if (nums.size() < 2) return 0;//特判,size为0,1不可能出现逆序对
vector<int> temps(nums.size());
mergeSort(nums, temps, 0, nums.size() - 1);
return cnt;
}
//归并排序
void mergeSort(vector<int>& nums, vector<int>& temps, int left, int right) {
if (left < right) {
int center = left + (right - left) / 2;
mergeSort(nums, temps, left, center);//左分
mergeSort(nums, temps, center + 1, right);//右分
merge(nums, temps, left, center, right);//治
}
}
//合并
void merge(vector<int>& nums, vector<int>& temp, int left, int center, int right) {
int i = left, j = center + 1;
for (int k = left; k <= right; k++) {
if (i > center) {//左边的已经比较完,将右边的全部放到temp中
temp[k] = nums[j++];
}
else if (j > right) {//右边的已经比较完,将左边的全部放到temp中
temp[k] = nums[i++];
}
else if (nums[i] > nums[j]) {//左边大于右边,出现逆序对,
temp[k] = nums[j++];//取右边数组值
cnt += center - i + 1;//此处+1是因为center是等于right的,这里也是比归并排序多的一行代码
}
else//左边小于等于右边
{
temp[k] = nums[i++];//取左边数组值
}
}
//将temp中的元素复制到nums中
for (int k = left; k <= right; k++) {
nums[k] = temp[k];
}
}
};