求排列的逆序数

描述

在Internet上的搜索引擎经常需要对信息进行比较,比如可以通过某个人对一些事物的排名来估计他(或她)对各种不同信息的兴趣,从而实现个性化的服务。

对于不同的排名结果可以用逆序来评价它们之间的差异。考虑1,2,…,n的排列i1,i2,…,in,如果其中存在j,k,满足 j < k 且ij > ik,那么就称(ij,ik)是这个排列的一个逆序。

一个排列含有逆序的个数称为这个排列的逆序数。例如排列 263451 含有8个逆序(2,1),(6,3),(6,4),(6,5),(6,1),(3,1),(4,1),(5,1),因此该排列的逆序数就是8。显然,由1,2,…,n 构成的所有n!个排列中,最小的逆序数是0,对应的排列就是1,2,…,n;最大的逆序数是n(n-1)/2,对应的排列就是n,(n-1),…,2,1。逆序数越大的排列与原始排列的差异度就越大。

现给定1,2,…,n的一个排列,求它的逆序数。



输入


第一行是一个整数n,表示该排列有n个数(n <= 100000)。
第二行是n个不同的正整数,之间以空格隔开,表示该排列。

输出


输出该排列的逆序数。

样例输入


6
2 6 3 4 5 1

样例输出


8

提示


1. 利用二分归并排序算法(分治);

2. 注意结果可能超过int的范围,需要用long long存储。


思路:就像题目的提示一样,利用归并排序,一边排序,一边统计此时的逆序数,最后将结果累加就可以,注意数字的范围!

import java.util.*;
public class Merge_Sort {
	static int[] a;
	static int[] tmp;
	static long sum = 0;
	static long merge(int a[],int tmp[],int start,int end,int center){
		//将数组a的局部a[s,center]和a[center + 1,e]合并到tmp,并保证tmp有序,然后再拷贝回a[s,m]   
		//归并操作时间复杂度:O(e-m+1),即O(n) 
		int pb = 0;
		int p1 = start , p2 = center + 1;
		long k = 0;
		
		while (p1 != center + 1){        //在这里开始这个部分的统计,具体为什么是center+1,自己试试吧
	        while (p2 != end + 1 && a[p1] < a[p2]){
	            p2++;
	        }
	        k += end - p2 + 1 ;             //统计属于a[p1]的逆序数,之后累加
	        p1++;
	    }
		
		p1 = start;                     //统计完之后进行数值的归位,进行下一次的归并
		p2 = center + 1 ;
		
		while( p1 <= center && p2 <= end){
			if( a[p1] > a[p2])
				tmp[pb++] = a[p1++];
			else
				tmp[pb++] = a[p2++];
		}
		while( p1 <= center)
			tmp[pb++] = a[p1++];
		while( p2 <= end)
			tmp[pb++] = a[p2++];
		for(int i=0;i<=end-start;i++){
			a[start + i] = tmp[i]; 
		}
		return k;
	}
	static void merge_Sort(int a[],int tmp[],int start,int end){
		if( start < end){
			int center = start + (end - start) / 2;
			merge_Sort(a, tmp, start, center);
			merge_Sort(a, tmp, center + 1, end);
			sum += merge(a, tmp, start, end, center);   //将所有的逆序数统计结果相加
		}
	}
	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		int n;
		System.out.print("Please input arrays length:");
		n = input.nextInt();
		a = new int[n];
		tmp = new int[n];
		for(int i = 0 ; i < a.length;i++){
			a[i] = input.nextInt();
		}
		merge_Sort(a, tmp, 0, n-1);
		/*for(int i = 0 ; i < a.length;i++)
			System.out.print(a[i] + " ");
		System.out.println();*/
		System.out.println(sum);
	}
}
/*
6
2 6 3 4 5 1
*/

运行结果:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值