前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >求解逆序对的个数(由归并排序衍生出的O(nlogn)时间复杂度的算法)

求解逆序对的个数(由归并排序衍生出的O(nlogn)时间复杂度的算法)

作者头像
lexingsen
发布2022-02-25 08:25:53
3670
发布2022-02-25 08:25:53
举报
文章被收录于专栏:乐行僧的博客

逆序:在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。

一、暴力做法

代码语言:javascript
复制
int count(int *a, int n) {
	int res = 0;
	for (int i=0; i<n-1; ++i) {
		for (int j=1; j<n; ++j) {
			if (a[i] > a[j]) res ++;
		}
	}
	return res;
}

可以看到,上边算法的时间复杂度为O(n^2),有没有效率更高的算法呢,其实在归并排序中,当进行两个有序数组合并时就会两两元素的比较。此时会出现,当第一个数组的某元素a[i]大于第二数组中的某元素a[j]时,则一个数组处于[i, m]区间的所有元素都会大于第二个数组的当前元素a[j]。这样做的好处是不需要将数组中的元素依次进行两两比较,一次比较就能处理一个大区间,因此算法的效率得到了提升。

二、归并排序

代码语言:javascript
复制
#include <iostream>
using namespace std;

typedef long long ll;
const int N=1e5+10;
ll a[N], t[N];
ll res = 0;

void mergeSort(ll *a, int l, int r) {
	if (l>=r) return;
	int m = (r-l)/2 + l;
	mergeSort(a, l, m);
	mergeSort(a, m+1, r);
	//i为第一个区间的起始下标  第一个区间[l, m]
	//j为第二个区间的起始下标  第二个区间[m+1, r]
	//k为临时数组的起始下标
	int i = l, r = m+1, k = 0;
	while (i <= m && j <= r) {
		if (a[i] <= a[j]) t[k ++] = a[i ++];
		else {
			//a[i] > a[j] && i < j 构成了逆序对  而此时 a[i]到a[m]的所有元素均大于a[j]  
			//a[i,....,m]的长度为  m-i+1
			res += m-i+1;
			t[k ++] = a[j ++];
		}
	}	
	while (i <= m) t[k ++] = a[i ++];
	while (j <= r) t[k ++] = a[j ++];
	for (int i=l, k=0; i<=r; ++i, ++k) a[i] = t[k];
}


int main() {
	ios::sync_with_stdio(false);
	int n;
	cin >> n;
	for (int i=0; i<n; ++i) cin >> a[i];
	mergeSort(a, 0, n-1);
	cout << res << endl;
	return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档