算法学习——利用归并排序求逆序对的数量
首先明白逆序对的定义,逆序对就是数组中两个元素前大后小,我们就称这两个元素为一组逆序对。
接着看题目:

我们利用分治的思想,将区间一分为二,然后得到了逆序对的存在情况共三种:
1.两个元素都在左侧区间。
2.两个元素都在右侧区间。
3.两个元素一个在左,一个在右。
那么很明显我们分治的去解决这个问题,就得到解法,
1.将区间划分成左右两个区间
2.递归左右两个区间
3.统计逆序对数量(1)+(2)
4.计算逆序对数量(3)
5.返回相应的结果。
那么问题来了,逆序对(1)(2)的情况都很容易理解怎么求,但是情况(3)的逆序对我们该怎么样求数量呢?
大佬给的方法是这样的:我们已经将区间划分成为了左右两个区间,我们只需要统计,对于右区间中的每一个元素,在左区间内有多少元素比他大,满足左大右小就可以了。这个时候我们想到了归并排序的合并过程,就是利用两个指针,分别对两个区间的元素进行比较,然后把小的元素放进临时数组里,并且将对应的指针往后移动。由于归并排序的左右区间大小是确定的,左区间有(L+R)/2个元素,所以我们利用这点,当右区间的指针每次需要移动的时候,就表示左区间内当前剩余的所有元素都是比他大的,也就是说,对于右区间指针所指的当前元素,存在有 【左区间剩余的所有元素数量】个逆序对。核心就是这些,接下来是代码。
#include<iostream>
using namespace std;
typedef long long LL;
const int N = 1e5 +10;
int a[N],tmp[N];
LL merge_sort(int l,int r){
if(l>=r)return 0;
int mid = l + r >> 1;
LL res = merge_sort(l,mid)+merge_sort(mid+1,r);
//归并过程
int k = 0,i = l,j = mid+1;
while(i<=mid && j<=r){
if(a[i]<=a[j]){
tmp[k++] = a[i++];
}else{
res += mid-i+1;
tmp[k++] = a[j++];
}
}
//回收
while(i<=mid) tmp[k++] = a[i++];
while(j<=r) tmp[k++] = a[j++];
for(int i = l,j = 0;i<=r;i++,j++)
a[i] = tmp[j];
return res;
}
int main(){
int n = 0;
cin>>n;
for(int i=0;i<n;i++)cin>>a[i];
cout<<merge_sort(0,n-1)<<endl;
return 0;
} 相关推荐
nongfusanquan0 2020-08-18
Broadview 2020-07-19
数据与算法之美 2020-07-05
Masimaro 2020-06-21
wonner 2020-06-17
Oudasheng 2020-06-04
从零开始 2020-06-05
清溪算法君老号 2020-06-01
风吹夏天 2020-05-26
yangjingdong00 2020-05-11
Tips 2020-04-30
troysps 2020-04-26
ustbfym 2020-04-25
清溪算法君老号 2020-04-24
dushine00 2020-04-19
数据与算法之美 2020-04-18
wulaxiaohei 2020-04-17
nurvnurv 2020-04-16