题目描述:
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
示例
输入 1,2,3,4,5,6,7,0
输出 7
思路分析:
方法1:
遍历数组,依次找出后面小于的数。该方法属于暴力查找,时间复杂度O(N^2),运行超时。
public class Solution {
public int InversePairs(int [] array) {
if(array == null || array.length < 2){
return 0;
}
int temp = 0;
for(int i = 0 ; i<array.length-1; i++){
for(int j = i+1 ; j < array.length ; j++){
if(array[i]>array[j]){
temp++;
}
}
}
return temp%1000000007;
}
}
方法2:
利用归并排序的思想解决问题。
归并排序的思想是分而治之,将数组分为两段,每段分别排序,再将两段排序后的数组组合在一起形成最终的数组。
故,我们先记录第一段没有排序之前时,出现的逆序对的个数。以及第二段原数组出现逆序对的个数。再计算两段数组之间出现的逆序对的个数。三者之和即为求得的最终结果。
重点是如何计算两段数组之间出现的逆序对。
1,设置两个指针分别指向两段数组的末尾(p1表示前一段数组的指针,p2表示后一段数组的指针),再新建一个辅助数组,长度是两段数组之和。
2,比较p1和p2位置数字的大小,若arr1[p1]>arr2[p2],则p2之前的所有数字均小于p1,该值也就是p1形成的逆序对,并将arr1[p1]放入辅助数组的末尾,p1向前移动一位。若arr1[p1]<arr2[p2],则将p2指针所指的数字存入辅助数组,p2指针向前移动一位。后面的思路和归并排序就是一样了。
public class Solution {
//尝试归并排序的思想。
public int InversePairs(int [] array) {
if(array == null || array.length < 2){
return 0;
}
int num = merge(array,0,array.length-1);
return num%1000000007;
}
public int merge(int[] arr , int l, int r){
if(r<=l){
return 0;
}
int mid =(l+r)/2;
int leftnum = merge(arr,l,mid)%1000000007;
int rightnum = merge(arr,mid+1,r)%1000000007;
int mergenum = mergeSort(arr,l,mid,r);
return (leftnum+rightnum+mergenum)%1000000007;
}
public int mergeSort(int[] arr, int l, int m, int r){
int[] help = new int[r-l+1];
int h = r-l;
int p1 = m;
int p2 = r;
int count = 0;
while(p1>=l && p2>m){
if(arr[p1]>arr[p2]){
count += p2-m;
if(count>=1000000007){
count%=1000000007;
}
help[h--] = arr[p1--];
}else{
help[h--] = arr[p2--];
}
}
while(p1>=l){
help[h--] = arr[p1--];
}
while(p2>m){
help[h--] = arr[p2--];
}
for(int i = 0 ; i < help.length; i++){
arr[l+i] = help[i];
}
return count;
}
}
public class Solution {
//尝试归并排序的思想。
public int InversePairs(int [] array) {
if(array == null || array.length < 2){
return 0;
}
int[] help = new int[array.length];
int num = merge(array,help,0,array.length-1);
return num%1000000007;
}
public int merge(int[] arr ,int[] help ,int l, int r){
if(r<=l){
return 0;
}
int mid =(l+r)/2;
int leftnum = merge(arr,help,l,mid)%1000000007;
int rightnum = merge(arr,help,mid+1,r)%1000000007;
int mergenum = mergeSort(arr,help,l,mid,r);
return (leftnum+rightnum+mergenum)%1000000007;
}
public int mergeSort(int[] arr, int[] help, int l, int m, int r){
int h = r;
int p1 = m;
int p2 = r;
int count = 0;
while(p1>=l && p2>m){
if(arr[p1]>arr[p2]){
count += p2-m;
if(count>=1000000007){
count%=1000000007;
}
help[h--] = arr[p1--];
}else{
help[h--] = arr[p2--];
}
}
while(p1>=l){
help[h--] = arr[p1--];
}
while(p2>m){
help[h--] = arr[p2--];
}
for(int i = l ; i <= r; i++){
arr[i] = help[i];
}
return count;
}
}