题目描述:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。例如,在数组{7,5,6,4}中,一共存在5个逆序对,分别是(7,6)、(7,5)、(7,4)、(6,4)、(5,4)。
分析:可以用类似归并排序的思想,将数组二分,直到数组中只有一个元素时,此时数组逆序数组个数为0,然后开始合并数组,分别统计两个合并数组中逆序对的个数,这样自底向上地完成数组的排序及逆序对的统计,实际上是和归并排序是相同的方法。
具体地对于计算统计两个子数组的逆序对的个数,我们用两个指针分别指向两个子数组的末尾,并每次比较两个指针指向的数字,如果第一个子数组中的数字大于第二个子数组中的数字,则构成逆序对,并且逆序对的数目等于第二个子数组中剩余数字的个数。如果第一个数组中的数字小于或等于第二个数组中的数字,则不构成逆序对。每次比较,我们都把较大的数字从后往前复制到一个辅助数组,确保辅助数组中的数字是递增排列。
int InversePairs(int* data,int length){if(data == nullptr || length < 0){return 0;}int* copy = new int[length];for(int i = 0;i < length;++i){ //用一个辅助数组存放排序后的数组元素copy[i] = data[i]; //****归并排序需要将辅助数组元素merge回原数组完成排序*****//}int count = InversePairsCore(data,copy,0,length - 1);//如果要保存排序后的数组可将data和copy参数交换位置:即InversePairCore(copy,data,0,length - 1);delete[] copy;return count;
}int InversePairsCore(int* data,int* copy,int start,int end){if(start == end){ //数组中只有一个元素,返回0// copy[start] = data[start]; return 0;}int length = (end - start) / 2;int left = InversePairsCore(copy,data,start,start + length); //copy数组中存放已排序的子数组,接下来会对copy数组作合并和排序操作,//操作的结果放在data数组中,作为下一次合并排序的copy数组(即两个数组,是互相备份的关系), //***此操作也修改了原输入数组中的元素值***int right = InversePairsCore(copy,data,start + length + 1,end);//i初始化为前半段最后一个元素的一下标int i = start + length;//j初始化为后半段最后一个元素的一下标int j = end;int indexCopy = end; //辅助数组的下标元素从数组结尾开始int count = 0;while(i >= start && j >= start + length + 1){if(data[i] > data[j]){copy[indexCopy--] = data[i--];count += j - start - length;}else{copy[indexCopy--] = data[j--];}}for(;i >= start;--i){copy[indexCopy--] = data[i];}for(;j >= start + length + 1;--j){copy[indexCopy--] = data[j];}return left + right + count;
}