merge_sort——逆序对的数量(归并排序)
思路:
1.暴力做法:两重循环一个个例举,第一层循环,i-> n ,第二层循环,j=i+1->n ,例如先例举i=2,j=3,4,5,6,1.,然后例举i=3,j=4,5,6,1。但是一般情况下会超时
2 归并排序:递归回溯,从小到大地合并,两个子序列,左边(l,mid),右边(mid+1,r),两个序列比较,当左边到进行到i时,q[i]>q[j],那么后面的mid-i个数都比去此时的q[j]大,即有mid-i+1个逆序对(i左边的序列,j是右边的序列)。用一个数记录个数,注意题目数据范围可能会爆int,所以用long long
如果您对归并排序还不了解,请您移步这篇博客 https://www.cnblogs.com/expect-999/p/17599008.html
如下图举例
从下到上回溯 (先左边回溯完,再右边回溯)
左逆序对 | (9,1)| (7,6)|,|(9,6)|(9,7) 数量 1+1+1+1
右逆序对 | (6,3) |(3,2),(6,2) | 数量 1+2
最终左右合并 逆序对 |(6,2),(7,2),(9,2)|(6,3),(7,3),(9,3)|(7,6),(9,6)|(9,8)| 数量 3+3+2+1
所以统计次数就每次 cnt+=mid-i+1;,即cnt=1+1+1+1+1+2+3+3+2+1=16;
运行实例结果如下图
先回溯左边,再回溯右边
C++代码如下
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
int n;
int q[N],p[N];
long long ans;
void merge_sort(int q[],int l,int r)
{
if(l>=r) return;
int mid = l + r >> 1;
merge_sort(q,l,mid);
merge_sort(q,mid+1,r);
int i=l,j=mid+1,cnt=0;
// int tmp=ans;
while(i<=mid && j <=r)
{
if(q[i]<=q[j]) p[cnt++]=q[i++];
else
{
p[cnt++]=q[j++];
ans+=mid-i+1;
// printf("%d ",mid-i+1);
}
}
// if(ans>tmp) puts("");
while(i<=mid) p[cnt++]=q[i++];
while(j<=r) p[cnt++]=q[j++];
for(int i=l,cnt=0;i<=r;) q[i++]=p[cnt++];
}
signed main()
{
cin >> n;
for(int i=0;i<n;++i) cin >> q[i];
merge_sort(q,0,n-1);
cout << ans <<endl;
return 0;
}
本人蒟蒻,如有错误或不恰当的地方还望指点,如果对您有帮助,希望给个免费的点赞,这对我很重要,感谢观看我的博客