算法学习之数组中的逆序对

题目描述

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数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)。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章