逆序对 归并排序求法 分治思想

本文介绍了如何利用分治思想和归并排序算法求解数组中的逆序对个数。首先定义逆序对的概念,然后通过暴力方法分析问题的复杂度。接着详细解释了分治策略的实现过程,特别是在有序子数组中如何高效地找出横跨左右的逆序对。最后,文章提供了一个完整的归并排序代码实现,强调了在排序过程中如何保持子数组信息的正确性以确保算法效率。
摘要由CSDN通过智能技术生成

逆序对介绍

如果存在正整数 i, j 使得 1 ≤ i < j ≤ n 而且 A[i] > A[j],则<A[i], A[j]> 这个有序对称为 A 的一个逆序对,也称作逆序数。

求解一个数组中逆序对个数

其实就是求下标小的大数,那么二话不说先来暴力,暴力显然是O(n2),8太行

int unseq(vector<int> &nums)
{
   
	int cnt = 0;
	for(int i=0; i<nums.size(); i++)
		for(int j=i+1; j<nums.size(); j++)
			if(nums[i]>nums[j]) cnt++;
	return cnt;
}

分治思想:借助归并排序

对于数组中的逆序对个数,将数组分为[l, mid][mid+1, r]区间,问题可以分解为子问题:

  • 子数组[l, mid]的逆序对个数 lcnt
  • 子数组[mid+1, r]的逆序对个数 rcnt
  • A[i]位于左边,A[j]位于右边 且 A[i] > A[j] 的 <i, j> 组成的对

问题 1,2可以递归地求解,那么关键是如何求问题3,即横跨左右的对

注意这里求解问题12的时候,不单单只是求解,还对数组排序了,也就是左边/右边都是有序的状态,那么我们可以用O(n)的时间,完成求解

  • 在右侧子数组中,从后往前枚举 j 下标
  • 在左侧子数组中,设置指针 i ,一开始 i 指向mid
  • i 向左滑动,找到第一个 i 使得 A[i]<=A[j]
  • 说明前面 i+1 ~ mid 下标,A[i] 都大于 A[j]
  • 那么对于 A[j] 为右边的逆序对,找到了 mid-i

因为两边都有序,那么对于 j 下标,因为A[j]是递减的,那么A[j+1]配对的个数,同样可以运用到A[j]上,此外还要额外判断A[j]是否能满足更多逆序对

这里利用两边数组的有序性,变相利用前面的结果,达到节省时间

看似两重循环,其实 i,j 回退不超过 n/2 次,所以复杂度O(n)

用O(n)时间找打横跨的逆序对个数,我们还要将数组归并,方便上一层递归继续查找

这里使用【inplace_merge函数】进行归并操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值