12月27日预备役刷题总结

求逆序数:

基本思路:归并排序,二分法;

所谓归并排序,即用递归对一个数组进行排序,归并排序分为拆分和合并两个过程,。以对一个数组升序为例,先递推将一个数组分为两个部分,从中间截开,一直分直到每个部分只剩一个数,然后开始递归合并,合并从两个只有一个数的部分开始,递归时不断将两个部分合成一个部分,在合成时要将小的数放在前面(以保证每次合成时的两个部分都是有序的),就这样一直合成直到回到原来要排序的数组,此时这个数组也是有序的,即这个数组升序,完成!举个栗子,比如说要将数组[5 2 4 7 8 1 3 2]升序,那么归并排序会将其分为[5],[2],[4],[7],[8],[1],[3],[2]几个部分,然后就合并:[2,5],[4,7],[1,8],[2,3],再一次合并:[2,4,5,7],[1,2,3,8],最后一次合并[1,2,2,3,4,5,7,8];可能不怎么好理解,直接看我写的函数

拆分:

void merge_sort(int a[], int left, int right) {//切开
	if (left < right) {//拆分结束条件
		int mid = (left + right) / 2;//从中间分开
		merge_sort(a, left, mid); //把左边部分沿中间分开
		merge_sort(a, mid + 1, right);//把右边部分沿中间分开
		merge(a, left, right, mid);//合并
	}
}

合并:

void merge(int a[], int left, int right, int mid) {//合并
	int s[100];//一个新数组用来存储排序好的数组
	int i = left, j = mid + 1;//两个变量分别指向左边和右边两组数的第一个数
	int sor = left;
	while (i <= mid && j <= right) {
		if (a[i] < a[j]) {//归并的过程
			s[sor++] = a[i++];
		} else {
			s[sor++] = a[j++];
		}
	}
	while (i <= mid) s[sor++] = a[i++];//当一组数已经全部排进去之后,再将另外一组剩余数都排进去
	while (j <= right)s[sor++] = a[j++];
	sor = left;
	while (sor <= right) {//把排好序的新数组全部放回原数组里
		a[sor] = s[sor];
		sor++;
	}
}

回归正题,本题思路:

读题,如果一对数前后位置与大小顺序相反,即i>j且arr[i]<arr[j],则arr[i]与arr[j]被称为一对逆序数,由归并排序的核心思想,本题就很容易联想到归并排序,归并排序每一次合并都会拿有序的两个部分的第一个元素进行比较,如果前一个元素大于后一个元素,这不正是逆序数吗?那么我们可以从这里入手,不多废话,直接看代码:

#include<stdio.h>
int nu[109900], s[109900], re = 0; //nu存储输入的数,s存储每次合并的部分
void mm(int a[], int left, int right, int mid) {
	int i = left, j = mid + 1;
	int sor = left;
	while (i <= mid && j <= right) {
		if (a[i] > a[j]) {//如果前面的元素比后面大,即l ~ mid中的元素 > mid + 1 ~ r中的元素,逆序数出现
			re += mid - i + 1;//由于l ~ mid和mid + 1 ~ r都是有序序列,故只要a[i]>a[j],那么a[i]~a[mid]就都会大于a[j],即逆序数总数就要加mid-i+1;
			//切记,不是re++;
			s[sor++] = a[j++];
		} else {
			s[sor++] = a[i++];
		}
	}
	while (i <= mid) s[sor++] = a[i++];
	while (j <= right)s[sor++] = a[j++];
	sor = left;
	while (sor <= right) {
		a[sor] = s[sor];
		sor++;
	}
}
void msort(int a[], int left, int right) {
	if (left < right) {
		int mid = (left + right) / 2;
		msort(a, left, mid); 
		msort(a, mid + 1, right);
		mm(a, left, right, mid);
	}
}
int main() {
	int T;
	scanf("%d", &T);
	getchar();
	for (int i = 1; i <= T; i++) {
		int num;
		re = 0;
		scanf("%d", &num);
		for (int io = 0; io < num; io++) {
			scanf("%d", &nu[io]);
		}
		msort(nu, 0, num - 1);
		printf("%d\n", re);
	}
	return 0;
}

羊了,今天写不动了~~~~~

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值