分治4--逆序对

逆序对

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

输入: arr[]={8,5,4,2,1}
输出: 10
解释: 逆序对为(8,5)、(8,4)、(8,2)、(8,1),(5,4)、(5,2)、(5,1),还有(4,2)、(4,1)和(2,1),总共10个。其实也可以直接计算5(5-1)/2=10,前提是知道数组完全逆序

输入: arr[]={5,1,4,2,8}
输出: 4
解释: 逆序对为(5,1)、(5,4)、(5,2),还有(4,2),总共4个。
在这里也可以看出数组{5,1,4,2,8}比{8,5,4,2,1}更有序,逆序对的数目可以衡量一个数组的有序程度。

关于归并排序的好多问题,一般都是从合并的角度进行考虑,统计逆序对同样如此。
我们以数组 [8,5,4,2,1] 为例进行具体讲解。
关于归并排序分的过程,就不在这里详细,直接看下图:
在这里插入图片描述
我们直接看合并过程中是如何统计逆序对的数目的,初始化逆序对的数目 count = 0 .
第一步,合并 8 和 5 ,8 > 5 ,为一个逆序对,count = count + 1 = 1

在这里插入图片描述
第二步,合并 [5,8] 和 4 ,5 > 4 ,因为 [5,8] 已经有序,所以 5 之后的元素都比 4 大,所以直接合并,而 count 的数目加 (mid+1) - (l + i) = 2 ,即逆序对就等于 count = 3 。说明,合并两个有序的数组,当第一个数组的指针 i 所指向的元素 大于后一个数组下标 j 所指向的元素,那么指针 i 所指向的元素及第一个数组中 i 之后的所有元素都应该大于第二个数组下标 j 所指向的元素,所以逆序对的数目应该加上 mid - i + 1 ,而我们给加上了 (mid+1) - (l + i) 是为了保证边界的准确性。

在这里插入图片描述
第三步,合并 2 和 1 ,2 > 1 ,是一个逆序对,所以 count 进行加一,即: count = 4

第四步,合并数组 [4,5,8] 和数组 [1,2] .

4 和 1 比较,4 > 1 ,所以 [4,5,8] 肯定均大于 1 ,逆序对的数目就加上 3 = (mid+1) - (l + i) , count = 7 。
在这里插入图片描述
然后 j 向右移动,即,j++ ;4 和 2 比较,4 > 2 ,所以 [4,5,8] 肯定均大于 1 ,逆序对的数目就加上 3 = (mid+1) - (l + i) ,count = 10 .

在这里插入图片描述
j 再向右移动,则会大于 r ,合并结束,逆序对的数目就是 count = 10 ,返回即可。

/*
	
*/

#include<iostream>
#include<cstdlib>
#include<time.h>
using namespace std;

int count = 0;

void merge(int arr[], int left, int mid, int right) {
    
    
	int p = left;
	int q = mid + 1;
	int * temp = new int[right - left + 1];
	int cnt = 0;
	while(p <= mid && q <= right) {
    
    
		if(arr[p] > arr[q]) {
    
    
			count += mid - left + 1;
			temp[cnt++] = arr[q++];
		} else {
    
    
			temp[cnt++] = arr[p++];
		}
	} 
	while(p <= mid) {
    
    
		temp[cnt++] = arr[p++];
	}
	while(q <= mid) {
    
    
		temp[cnt++] = arr[q++];
	}
	for(int i = 0; i < cnt; i++){
    
    
		arr[left + i] = temp[i];
	}
	delete []temp;
}

int mergesort(int arr[], int left, int right) {
    
    
	if(left < right) {
    
    
		int mid = left + ((right - left) >> 1);
		mergesort(arr, left, mid);
		mergesort(arr, mid + 1, right);
		merge(arr, left, mid, right);
	}
}

int main() {
    
    
	int arr[] = {
    
    8, 5, 4, 2, 1};
	mergesort(arr, 0, 4);
	cout<<count;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44227389/article/details/107854903
4--