1,问题描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007。
- 输入描述:题目保证输入的数组中没有的相同的数字,数组大小的范围:
- 对于%50的数据,size<=10^4
- 对于%75的数据,size<=10^5
- 对于%100的数据,size<=2*10^5
2,解题思路
有两种解题思路:
(1)遍历整个数组,将遍历元素与其之后的元素一一比较,有小于其的,逆序对数加1。这种方法想法简单,但是复杂度过高,只能通过50%。
(2)转自牛客, 归并排序的改进。
把数据分成前后两个数组(递归分到每个数组仅有一个数据项),合并数组。合并时,出现后面的数组值array[j]小于前面数组值array[i]时;则后面数组array[mid+1]~array[j]都是小于array[i]的,count += (j-mid)。参考剑指Offer,但是感觉剑指Offer归并过程少了一步拷贝过程。还有就是测试用例输出结果比较大,需要对每次返回的count mod(1000000007)求余。
3,源码
(1)第一种方法源码
public class Solution {
public int InversePairs(int [] array) {
int n = array.length;
int count = 0;
for(int i = 0;i<n-1;i++){
for(int j = i+1; j<n; j++){
if(array[j] < array[i]){
count++;
}
}
}
return count%1000000007;
}
}
(2)第二种方法源码
public class Solution {
public int InversePairs(int [] array) {
int n = array.length;
if(n <= 1){
return 0;
}
int[] copy = new int[n];
//for(int i=0;i<n;i++){
// copy[i] = array[i];
//}
int count = InversePairsCore(array,copy,0,n-1);
return count;
}
public static int InversePairsCore(int[] array, int[] copy, int start, int end){
if(start>=end){
return 0;
}
int mid = (start+end)>>1;
int count = 0;
//递归的过程,即,不断拆解、统计逆序对、排序和合并的过程。
int leftCount = InversePairsCore(array,copy,start,mid)%1000000007;
int rightCount = InversePairsCore(array,copy,mid+1,end)%1000000007;
int i = mid;
int j = end;
int copyIndex = end;
//从左右子数组的最后一个元素开始对比,直到遍历完其中的一个子数组
while(i>=start && j>mid){
if(array[i] > array[j]){
count += j-mid;
//每比较一次,copy数组确定一个最终元素。
copy[copyIndex--] = array[i--];
if(count>=1000000007){
count%=1000000007;
}
}else{
copy[copyIndex--] = array[j--];
}
}
//接下来的两个循环是将左右子数组中剩余的有序部分拷贝到copy数组。
while(i>=start){
copy[copyIndex--] = array[i--];
}
while(j>mid){
copy[copyIndex--] = array[j--];
}
//统计完逆序对后,将原始数组的该部分变成有序数组,即,合并、排序的过程。
for(int k = start; k<=end;k++){
array[k] = copy[k];
}
return (leftCount+rightCount+count)%1000000007;
}
}