【问题】在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。即输出P%1000000007
输入描述:
题目保证输入的数组中没有的相同的数字
数据范围:
对于%50的数据,size<=10^4
对于%75的数据,size<=10^5
对于%100的数据,size<=2*10^5
【思路】基于归并排序的思想统计逆序对:先把数组分割成子数组,再子数组合并的过程中统计逆序对的数目。统计逆序对时,先统计子数组内部的逆序对的数目,再统计相邻子数组的逆序对数目。
注:图中省略了最后一步,即复制第二个子数组最后剩余的4到辅助数组中。(a) P1指向的数字大于P2指向的数字,表明数组中存在逆序对。P2指向的数字是第二个子数组的第二个数字,因此第二个子数组中有两个数字比7小。把逆序对数目加2,并把7复制到辅助数组,向前移动P1和P3。(b) P1指向的数字小于P2指向的数字,没有逆序对。把P2指向的数字复制到辅助数组,并向前移动P2和P3. (c) P1指向的数字大于P2指向的数字,因此存在逆序对。由于P2指向的数字是第二个子数组的第一个数字,子数组中只有一个数字比5小。把逆序对数目加1,并把5复制到辅助数组,向前移动P1和P3。
#include <iostream> #include <vector> using namespace std; class Solution{ public: int count=0; int InversePairs(vector<int> data) { // 检查边界条件 if(data.size() != 0) { MergeSort(data,0,data.size()-1); } return count; } private: void MergeSort(vector<int> a, int l, int r) { /* 将长度为n的输入序列分成两个长度为n/2的子序列 */ if (l < r) { /* 中间元素*/ int m = (l + r) >>1; // 递归拆分 MergeSort(a, l, m); MergeSort(a, m + 1, r); // 递归合并 Merge(a, l, m, r); } } void Merge(vector<int> a, int l, int m, int r) { vector<int> t; //int p = 0; /* p指向辅助数组 */ int i = l; /* i指向第一个子表 */ int j = m + 1;/* j指向第二个子表 */ /* 两个子表都不为空时 */ while(i <= m && j <= r) { /* 取关键字小的元素转移至临时数组 */ if (a[i] > a[j]) { t.push_back(a[j++]); count=(count+m-i+1)%1000000007; } else t.push_back(a[i++]); } while(i <= m) t.push_back(a[i++]);/* 将非空的输入区间转移至输出区间 */ while(j <= r) t.push_back(a[j++]); for (i = 0; i < t.size(); i++) a[l + i] = t[i];/* 归并完成后将结果复制到原输入数组 */ } }; int main() { vector<int> a = {8,7,6,5,455,88,888,9999,546,46548,1315,445,554,111,5222,2264,8,331,454548}; Solution solution; solution.InversePairs(a); return 0; }