题目描述:
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数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];
}

1715

被折叠的 条评论
为什么被折叠?



