题目的链接在这里:https://www.nowcoder.com/practice/96bd6684e04a44eb80e6a68efc0ec6c5
题目大意
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P mod 1000000007数据范围: 对于 50%50% 的数据, size\leq 10^4size≤10
4
对于 100%100% 的数据, size\leq 10^5size≤10
5
数组中所有数字的值满足 0 \le val \le 10000000≤val≤1000000
要求:空间复杂度 O(n)O(n),时间复杂度 O(nlogn)O(nlogn)
一、示意图
二、解题思路
归并排序
归并排序
代码如下:
public class Solution {
int count=0;
int[]temp;
public int InversePairs(int [] array) {
//数组中的逆序对 前一个数字大于后一个 那就是一个逆序对 两个数组成一个逆序对
temp=new int[array.length];
mergeSort(array,0,array.length-1);
return count;
}
private void mergeSort(int[] array, int left, int right) {
if(left>=right)
return;
int mid=(left+right)/2;
//然后排其中两个序
mergeSort(array,left,mid);
mergeSort(array,mid+1,right);
merge(array,left,mid,right);
}
//合并left mid mid+1 right 这两个有序数组的同时 计算逆序对
private void merge(int[] array, int left, int mid, int right) {
int i=left;
int j=mid+1;
int k=left;
//当前面数组也就是i指针移动的时候 在j之前的都是比i小的元素
//这里合并的思路就是 两边比大小 然后把小的赋值
while (i<=mid&&j<=right){
//说明右边的更大一点
if(array[i]<=array[j]){
temp[k++]=array[i++];
//为什么是j-mid-1呢 当i比j要小的时候
// count=(count+(j-mid-1))%1000000007;
}
else {
//因为归并排序是从小到大的有序排序 所以一旦出现 i比j大的情况的话 就说明i比j之前的都要大
//mid前面又多少个j比当前的temp要小 可以这么理解 i向前移动了多少步 就说明
//合并的时候 left到mid 这个小的已经有序了 而mid+1 到right也已经有序了
//换个思路来说 那也就是 i之后到mid的 都比当前的j要大 那就可以以当前j为终点 进行一波更新
count=(count+(mid-i+1))%1000000007;
temp[k++] = array[j++];
}
}
//前面总有一个会还没结束的
while (i<=mid){
temp[k++]=array[i++];
//最关键的是这个统计的数量
// count=(count+(right-mid))%1000000007;
}
while (j<=right){
temp[k++]=array[j++];
}
//然后把temp的值转入到array之中
for(int index=left;index<=right;index++){
array[index]=temp[index];
}
}
}