题目:
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
思路:
归并思想
把数组分成前后两部分,逆序对数就等于前面的逆序对数 + 后面的逆序对数 + 前面和后面组合的逆序对数(一个前面的数一个后面的数)
以7,5,6,4为例,分成两部分{7,5}和{6,4},{7,5}和{6,4}都是逆序对,count=2(逆序对数 + 后面的逆序对数);
将{7,5}和{6,4}分别排序(避免重复)为{5,7}和{4,6},7大于6,则7大于6前的所有数,count=count+2=4;
前面数组的指针向前移,指向5,5不大于6,后面数组的指针向前移,指向4,5大于4,是逆序对,count+1=5。
copy就是用来排序的,两部分合并之后是排好序的,排好序放到array中对应的位置供后面使用,怎么排序呢,就是找逆序对的时候比较大小,将大的从后向前依次放,找完了逆序对,顺序也排好了。
代码:
public class Solution {
public int InversePairs(int [] array) {
if(array.length == 0){
return 0;
}
int sum = count(array, 0, array.length-1);
return sum;
}
private int count(int[] array, int start, int end){
if(start == end){
return 0;
}
int sum = 0;
int mid = (start + end)/2;
int left = count(array, start, mid); //左边的逆序对数
int right = count(array, mid+1, end); //右边的逆序对数
int count = 0; //计数,左右结合出现的逆序对数(一个逆序对里面,一个是左边的,一个是右边的)
int i = mid; //遍历左边的
int j = end; //遍历右边的
int[] copy = new int[end - start+1]; //辅助数组
int index = end - start;
while(i >= start && j >= mid+1){ //左右的数组有一个走完就结束
if(array[i] > array[j]){ //如果i位置的数大于j位置的数,
count += j - mid; //则mid到j的所有数都比i小
if(count > 1000000007){ //count大于1000000007时,count % 1000000007余数就不再是count了
count = count % 1000000007;
}
copy[index] = array[i]; //将大的数赋值给辅助数组
index--;
i--;
}else{
copy[index] = array[j];
index--;
j--;
}
}
//把左或右边没走完的,直接赋值给辅助数组
while(i >= start){
copy[index] = array[i];
i--;
index--;
}
while(j >= mid + 1){
copy[index] = array[j];
j--;
index--;
}
for(int r = 0; r <= end -start; r++){ //将排好序的数组放到array中对应的位置
array[start+r] = copy[r];
}
sum = (count + left +right) % 1000000007;
return sum;
}
}