左神基础班02、数组中的逆序对

题目描述:

     在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数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

原题链接:数组中的逆序对

解题思路:

1、归并排序 + 递归:

      可以利用归并排序的思想,基本过程和归并排序一样,只不过在合并两个子数组时统计逆序对数量即可。设两个排好序(逆序)的子数组分别为arr[l,mid]和arr[mid + 1,l],指针p1和p2分别指向左右子数组中的元素。具体的计算小和过程如下:

(1)当arr[p1] > arr[p2]时,则计算逆序对的数量,计算方式为res += r - p2 + 1,并将arr[p1]赋值给辅助数组help: help[i++] = arr[p1]

(2)当arr[p1] <= arr[p2]时,则不用计算小和,直接将arr[p2]赋值给辅助数组help: help[i++] = arr[p2]

递归终止条件:l == r,返回0。

注:(1)在每一步完成统计完逆序对的数量后,记得进行取余操作。

时间复杂度和空间复杂度: 时间复杂度为O(NlogN),空间复杂度为O(N)

实现代码:

public class Solution {

	//解法1:归并排序 + 递归
    public int InversePairs(int [] array) {
        if(array == null || array.length < 2)
            return 0;
        return inverseMerge(array, 0, array.length - 1);
    }
    
    public int inverseMerge(int[] arr, int l, int r){
        if(l == r)
            return 0;
        int mid = l + ((r - l) >> 1);
        int res = 0;
        //注意这里每一步都要取余
        res = (res + inverseMerge(arr, l, mid)) % 1000000007;
        res = (res + inverseMerge(arr, mid + 1, r)) % 1000000007;
        res = (res + merge(arr, l, mid, r)) % 1000000007;
        return res;
    }
    
    public int merge(int[] arr, int l, int mid, int r){
        int res = 0, i = 0;
        int p1 = l, p2 = mid + 1;
        int[] help = new int[r - l + 1];
        while(p1 <= mid && p2 <= r){
            res = (res + (arr[p1] > arr[p2] ? r - p2 + 1 : 0)) % 1000000007;
            help[i++] = arr[p1] > arr[p2] ? arr[p1++] : arr[p2++];
        }    
        while(p1 <= mid){
            help[i++] = arr[p1++];
        }
        while(p2 <= r){
            help[i++] = arr[p2++];
        }
        for(i = 0; i < help.length; ++i){
            arr[l + i] = help[i];
        }
        return res;
    }
}
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页