题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
输入描述:
题目保证输入的数组中没有的相同的数字数据范围: 对于%50的数据,size<=10^4 对于%75的数据,size<=10^5 对于%100的数据,size<=2*10^5
示例1
输入
复制
1,2,3,4,5,6,7,0
输出
复制
7
思路
直观解法就是for循环暴力解, 每扫描到一个数组的时候,逐个比较该数字和它后面的数字的大小。如果后面的数字比它小,则这两个数字就组成了一个逆序对。假设数组中含有n个数字。由于每个数字都要和O(n)这个数字比较,因此这个算法的时间复杂度为O(n^2)。 但是面试官肯定是不想要这种解法的,所以这里来想以数组{7,5,6,4}为例来分析统计逆序对的过程。每次扫描到一个数字的时候,我们不拿ta和后面的每一个数字作比较,否则时间复杂度就是O(n^2),因此我们可以考虑先比较两个相邻的数字。
(a) 把长度为4的数组分解成两个长度为2的子数组;
(b) 把长度为2的数组分解成两个成都为1的子数组;
© 把长度为1的子数组 合并、排序并统计逆序对 ;
(d) 把长度为2的子数组合并、排序,并统计逆序对;
在上图(a)和(b)中,我们先把数组分解成两个长度为2的子数组,再把这两个子数组分别拆成两个长度为1的子数组。接下来一边合并相邻的子数组,一边统计逆序对的数目。在第一对长度为1的子数组{7}、{5}中7大于5,因此(7,5)组成一个逆序对。同样在第二对长度为1的子数组{6}、{4}中也有逆序对(6,4)。由于我们已经统计了这两对子数组内部的逆序对,因此需要把这两对子数组 排序 如上图(c)所示, **以免在以后的统计过程中再重复统计。**这种方法很像归并排序,参考https://www.cnblogs.com/chengxiao/p/6194356.html
故有以下解法:
int count=0;
public int InversePairs(int [] array) {
if(array==null||array.length<=0) return 0;
mergeUp2Down(array,0,array.length-1);
return count;
}
public void mergeUp2Down(int [] a,int start,int end){
if(start>=end) return;
int mid=(end+start)>>1;
mergeUp2Down(a,start,mid);
mergeUp2Down(a,mid+1,end);
merge(a,start,mid,end);
}
public void merge(int [] a,int start,int mid,int end){
int[] temp=new int[end-start+1];
int i=start,j=mid+1,index=0;
while(i<=mid&&j<=end){
if(a[i]>a[j]) {
temp[index++]=a[j++];
count+=mid-i+1;
count=count>1000000007?count%1000000007:count;
}else temp[index++]=a[i++];
}
while(i<=mid) temp[index++]=a[i++];
while(j<=end) temp[index++]=a[j++];
for(int k=0;k<temp.length;k++) a[start+k]=temp[k];
}