题目描述:
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数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
原题链接:数组中的逆序对
解题思路:
1、归并排序 + 递归:
可以利用归并排序的思想,基本过程和归并排序一样,只不过在合并两个子数组时统计逆序对数量即可。设两个排好序(逆序)的子数组分别为arr[l,mid]和arr[mid + 1,l],指针p1和p2分别指向左右子数组中的元素。具体的计算小和过程如下:
(1)当arr[p1] > arr[p2]
时,则计算逆序对的数量,计算方式为res += r - p2 + 1,并将arr[p1]赋值给辅助数组help: help[i++] = arr[p1]
。
(2)当arr[p1] <= arr[p2]
时,则不用计算小和,直接将arr[p2]赋值给辅助数组help: help[i++] = arr[p2]
。
递归终止条件: 当l == r
,返回0。
注:(1)在每一步完成统计完逆序对的数量后,记得进行取余操作。
时间复杂度和空间复杂度: 时间复杂度为O(NlogN),空间复杂度为O(N)。
实现代码:
public class Solution {
//解法1:归并排序 + 递归
public int InversePairs(int [] array) {
if(array == null || array.length < 2)
return 0;
return inverseMerge(array, 0, array.length - 1);
}
public int inverseMerge(int[] arr, int l, int r){
if(l == r)
return 0;
int mid = l + ((r - l) >> 1);
int res = 0;
//注意这里每一步都要取余
res = (res + inverseMerge(arr, l, mid)) % 1000000007;
res = (res + inverseMerge(arr, mid + 1, r)) % 1000000007;
res = (res + merge(arr, l, mid, r)) % 1000000007;
return res;
}
public int merge(int[] arr, int l, int mid, int r){
int res = 0, i = 0;
int p1 = l, p2 = mid + 1;
int[] help = new int[r - l + 1];
while(p1 <= mid && p2 <= r){
res = (res + (arr[p1] > arr[p2] ? r - p2 + 1 : 0)) % 1000000007;
help[i++] = arr[p1] > arr[p2] ? arr[p1++] : arr[p2++];
}
while(p1 <= mid){
help[i++] = arr[p1++];
}
while(p2 <= r){
help[i++] = arr[p2++];
}
for(i = 0; i < help.length; ++i){
arr[l + i] = help[i];
}
return res;
}
}