题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
输入描述
题目保证输入的数组中没有的相同的数字
数据范围:
对于%50的数据,size<=10^4
对于%75的数据,size<=10^5
对于%100的数据,size<=2*10^5
示例
输入:1,2,3,4,5,6,7,0
输出:7
思路
本题运用归并排序,首先,序列中数字两两之间计算逆序对并排序,然后递归返回再计算两个区间之间的逆序对并排序,再返回,直至计算完整个序列的逆序对。排序是因为避免重复计算逆序对。
计算逆序对是在合并左右两个区间的过程中进行的,由于左区间的数应该都小于右区间的数,所以计算逆序对就是计算左区间大于右区间的数的总个数。从左至右同时遍历左右两个区间,如果此时左区间遍历到的数小于右区间遍历到的数,则左区间继续往右遍历;如果此时左区间遍历到的数大于右区间遍历到的数,由于左右区间本身是有序的,所以此时左区间遍历到的数及该数右面的所有数都大于右区间此时遍历到的数,那么右区间遍历到的数对应的逆序对就是左区间中遍历到的数及该数右面的所有数的个数,然后右区间继续往右遍历并累加逆序对,直至遍历完整个区间并将区间排序。
代码(c++)
class Solution {
public:
void Merge(vector<int> &data, int lleft, int lright, int rleft, int rright, int &res){
vector<int> temp;
int left = lleft;
while(lright>=lleft&&rright>=rleft){
if(data[lleft]<data[rleft]){
temp.push_back(data[lleft]);
lleft++;
}
else if(data[lleft]>data[rleft]){
temp.push_back(data[rleft]);
res=(res+(lright-lleft+1)%1000000007)%1000000007;
rleft++;
}
}
while(lright>=lleft){
temp.push_back(data[lleft]);
lleft++;
}
while(rright>=rleft){
temp.push_back(data[rleft]);
rleft++;
}
for(int i=0;i<temp.size();i++){
data[left++]=temp[i];
}
}
void MergeSort(vector<int> &data, int left, int right, int &res){
if(left<right){
int mid = (left + right) / 2;
MergeSort(data, left, mid, res);
MergeSort(data, mid+1, right, res);
Merge(data,left,mid,mid+1,right,res);
}
}
int InversePairs(vector<int> &data) {
int res=0;
MergeSort(data,0,data.size()-1,res);
return res;
}
};