数组中的逆序

 

Posted by     DH on August 22, 2017

题目

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。 并将P对1000000007取模的结果输出。 即输出P%1000000007

输入描述:

题目保证输入的数组中没有的相同的数字 数据范围: 对于%50的数据,size<=10^4 对于%75的数据,size<=10^5 对于%100的数据,size<=2*10^5

分析

最直观的思维就是从前往后,每次取数组的一个数,然后将这个数和它之后的的每一个数进行比较,如果大于他之后的数,总数就+1.

这个方法取每个数字,要取n次,比较也要n次,因此时间复杂度是O(n2)。

其实这个题,是归并排序的变种,并且只是需要在每次排序的时候,假如左边的元素比右边的元素大,那么左右两边的数组本来就是升序,假如左边数组的当前指针 索引是leftIndex,右边数组的当前指针是rightIndex,那么从leftIndex+1到mid,这之间的数都是大于leftIndex指向的数,mid+1到rightIndex-1之间的数都是 小于rightIndex指向的数的。

因此,如果左边数组的leftIndex > 右边数组的rightIndex。那么左边数组一定是大于mid+1指向的数,因此个数就是mid+1-leftIndex

至于详细的归并排序,可以参考我的排序算法的博客。

代码

public class Solution {
    int count;
 
    public int InversePairs(int[] array) {
        count = 0;
        if (array != null || array.length == 0)
            mergeSort(array, 0, array.length - 1);
        return count%1000000007;
    }
 
    public void mergeSort(int[] a, int left, int right) {
        if (left >= right)
            return;
        int mid = (left + right) >> 1;
 
        mergeSort(a, left, mid);
        mergeSort(a, mid + 1, right);
 
        merge(a, left, mid, right);
    }
 
    
    public void merge(int[] a, int left, int mid, int right) {
        int[] tmp = new int[right - left + 1];
 
        int leftIndex = left;
        int rightIndex = mid + 1;
        int tempIndex = 0;
        while (leftIndex <= mid && rightIndex <= right) {
            if (a[leftIndex] <= a[rightIndex])
                tmp[tempIndex++] = a[leftIndex++];
            else {
                tmp[tempIndex++] = a[rightIndex++];
                count += mid - leftIndex + 1;  
                count%=1000000007;
            }
        }
 
        while (leftIndex <= mid)
            tmp[tempIndex++] = a[leftIndex++];
        while (rightIndex <= right)
            tmp[tempIndex++] = a[rightIndex++];
        
        for (tempIndex = 0; tempIndex < tmp.length; tempIndex++) 
            a[left + tempIndex] = tmp[tempIndex];
    }
}