题目描述
给定一个长度为 n 的整数数列,请你计算数列中的逆序对的数量。
逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足i<j
且 a[i]>a[j]
,则其为一个逆序对;否则不是。
输入格式
第一行包含整数 n,表示数列的长度。
第二行包含 n 个整数,表示整个数列。
输出格式
输出一个整数,表示逆序对的个数。
数据范围
1≤n≤100000
,
数列中的元素的取值范围 [1,109]
。
输入样例:
6
2 3 4 5 6 1
输出样例:
5
解题思路:在归并排序的基础上寻找逆序对;在每次合并之前,先计算逆序对数,左右两组数此时皆是从小到大的顺序排列。若左边第一个数大于右边第一个数,则左边剩下的数皆可和右边第一个数形成逆序对;此时继续看右边第二个数,比较左边第一个数和右边第二个数,以此类推。若左边第一个数小于右边第一个数,则比较左边第二个数和右边第一个数,如上述同样方式类推。
#include <iostream>using namespace std;const int N = 4;
int q[N],tmp[N];
int z = 0; // 逆序对个数
// 归并排序 类似后序遍历
void merge_sort(int q[],int left,int right){if(left>=right) return;int mid = (left + right) >> 1; // 确定分界点merge_sort(q,left,mid); // 左子数组排序merge_sort(q,mid+1,right); // 右子数组排序/*统计逆序对*/int i = left, j = mid +1 ; while (i<=mid){while (j<=right){if(q[i]<q[j]){z+=right-j+1;break;}j++;}i++;}/*执行合并*/// 合并两子数组到tmp,k是tmp的指针,i,j指向左/右子数组头部int k=0;i = left, j = mid +1 ; while(i<=mid && j <=right){if(q[i]<=q[j])tmp[k++]=q[i++];else tmp[k++]=q[j++];}// 复制没到头的偏大一坨while(i <= mid)tmp[k++]=q[i++];while(j <= right)tmp[k++]=q[j++];// 把合并后的tmp 复制到 原数组for(i=left,j=0;i<right;++i,++j)q[i]=tmp[j];
}int main(){for(int i=N-1;i>=0;--i){q[i]=i;}merge_sort(q,0,N-1);for(int i=0;i<N;++i){cout << q[i] << " ";cout << endl;}cout << z;}