题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数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
思路,如果我们暴力一点,可以直接嵌套双遍历进行获取个数就完事了,可是这样,每次都拿出一个数跟其他比较,复杂度太大:n^2。所以这里使用了小套路:归并排序。现将数组分解成单个元素,然后两个相邻的进行比较,如果前边的打则符合条件,我们进行计数,并进行排序,防止下次重复计数。然后比较同一组的另外相邻的两个元素,同理。最后比较已两个为基本单位的两个组合,进行混合比较同时计数和排序。说起来可能有点蒙,这里为了方便理解盗了张图。这样至少节省了一般以上的时间成本。
import java.util.*;
public class Solution {
int count = 0;
public int InversePairs(int [] array) {
mergeSort(array,0,array.length-1);
return count;
}
// 归并排序开始,即递归形式把数组切割成单个元素,然后回马枪开始排序同时统计count
public void mergeSort(int [] array,int lo,int hi){
if(lo==hi)return;
int mid = (lo+hi)>>1;
mergeSort(array,lo,mid);
mergeSort(array,mid+1,hi);
merge(array,lo,mid,hi);
}
public void merge(int [] array,int lo,int mid,int hi){
// k记录当前辅助数组索引
// p1记录左半段开始索引位置
// p2记录右半段开始索引位置
int k = 0, p1 = lo,p2 = mid+1;
int [] copy = new int[hi-lo+1];
while(p1<=mid&&p2<=hi){
if(array[p1]>array[p2]){ // 前边大,说明p1处至p2处中间这些数都能与p1位置处组成逆序对
count=(count+(mid-p1+1))%1000000007;
copy[k++] = array[p2++]; // 把较小的放入到辅助数组
}else{
copy[k++] = array[p1++];
}
}
// 将剩余的赋值到辅助数组copy中
while(p1<=mid){
copy[k++] = array[p1++];
}
while(p2<=hi){
copy[k++] = array[p2++];
}
// 把辅助数组的值赋给相应位置的原数组,开始下次merge
for(int i = 0;i < k;i++){
array[i+lo] = copy[i];
}
}
}
- 时间复杂度:O(nlogn)。
- 空间复杂度:O(n)。