数组中的逆序对

题目描述:

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
题目保证输入的数组中没有的相同的数字
数据范围:

对于%50的数据,size<=10^4

对于%75的数据,size<=10^5

对于%100的数据,size<=2*10^5

样例:

输入:[1,2,3,4,5,6,0]
输出:6

分析:

首先把数组分成独立的个体,然后相互之间两两合并成长度为2的数组,在合并的过程中统计逆序对的数目。所有的个体合并完成之后,即组成了n对长度为2的数组;对长度为2的数组进行两合并,组成长度为4的数组,先用两个指针分别指向两个子数组的末尾,并每次比较两个指针指向的数字的大小,如果第一个子数组中的数字大于第二个子数组中的数字,则构成逆序对,并且逆序对的数目等于第二个子数组中剩余数字的个数。每次比较的时候,我们都把较大的数字从后往前复制到一个辅助数组,确保辅助数组中的数字是递增排序的。把较大的数字复制到辅助数组以后,相应的指针前移一位。

 public int InversePairs(int [] array) {
		if(array==null||array.length==0)
			return 0;
		int[] copy=new int[array.length];
		int count=merge(array,copy,0,array.length-1);
		return count;
	}
	
	private int merge(int[] array,int[] copy, int low, int high) {
		if(low==high) {
			copy[low]=array[low];
			return 0;
		}
		int mid=low+(high-low)/2;
		int left=merge(array,copy,low,mid)%1000000007;
		int right=merge(array,copy,mid+1,high)%1000000007;
		int i=mid,j=high,k=high;
		int count=0;
		while(i>=low&&j>mid) {
			if(array[i]>array[j]) {
				count+=j-mid;
				copy[k--]=array[i--];
				//数值过大求余
				if(count>=1000000007)
					count%=1000000007;
			}else {
				copy[k--]=array[j--];
			}
		}
		while(i>=low)
			copy[k--]=array[i--];
		while(j>mid)
			copy[k--]=array[j--];
		for(int p=low;p<=high;p++)
			array[p]=copy[p];
		return (left+right+count)%1000000007;
	}
//暴力法 在牛客上超时
	public int InversePairs(int [] array) {
		if(array==null||array.length==0)
			return 0;
		int[] dp=new int[array.length];
		int min=array[array.length-1],mini=array.length-1;
		for(int i=array.length-2;i>=0;i--) {
			if(array[i]>min) {
				dp[i]=1;
				dp[i]+=dp[i+1];
				for(int j=mini+1;j<array.length;j++) {
					if(array[i]>array[j])
						dp[i]++;
				}
				for(int j=mini-1;j>i;j--) {
					if(array[i]>array[j]) {
						dp[i]++;
					}
				}
			}else {
				min=array[i];
				mini=i;
				dp[i]=dp[i+1];
			}
			
		}
        return dp[0];
    }
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值