问题描述:统计一个数组中共有多少个逆序对
输入:
第一行一个整数n,第二行n个整数
输出:
这n个数构成的数组中逆序对的总数
解题思路:
如果用蛮力枚举法,则对每个a[i],枚举j(j>i),并统计逆序对数目
参考如下代码:
int CountInver(int a[],int n){
int s=0;
for(int i=1;i<=n-1;i++)
for(int j=i+1;j<=n;j++)
if(a[j]<a[i]) s++;
return s;
}
平均时间复杂度为O(n^2)
采用分而治之的思想:将数组一分为二,递归求解子数组的逆序对,再合并问题解,关键在于求解跨越子数组的逆序对数目,
可以采用直接求解,或先排序再进行二分查找求解,平均时间复杂度分别为
O
(
n
2
)
,
O
(
n
(
l
o
g
n
)
2
)
O(n^2) ,O(n(logn)^2)
O(n2),O(n(logn)2)相比蛮力枚举效率变化不大还是很低,致因在于我们没有将排序过程融入整个算法框架,为了解决这个问题,我们可以采用归并排序,那么统计逆序对问题的整个算法就和归并排序相似,只是稍加改变
参考代码如下:
int MergeCount(int a[],int left,int mid,int right);
int CountInver(int a[],int left,int right){
int S1,S2,S3;
if(left>=right) return 0;
else{
int mid=(left+right)/2;
S1=CountInver(int a[],left,mid);
S2=CountInver(int a[],mid+1,right);
S3=MergeCount(int a[],left,mid,right);
return S1+S2+S3;
}
}
int MergeCount(int a[],int left,int mid,int right){
int b[right+1],i,j=mid+1,k=left,s=0; //数组下标为0位置不存放数据
for(i=left;i<=right;i++) b[i]=a[i];
i=left;
while(i<=mid&&j<=right){
if(b[i]<=b[j]) a[k++]=b[i++];
else {a[k++]=b[j++];s+=(mid-i+1);
}
if(i<=mid) while(i<=mid) a[k++]=b[i++];
if(j<=right) while(j<=right) a[k++]=b[j++];
return s;
}
平均时间复杂度为:O(nlogn)
☞归并排序