金九银十之小数之和

174 阅读1分钟

文字题解

小数就是在一个数组中,当右边的数大于左边的数,那么左边的这个数就是小数
利用归并排序实现

在归并排序执行过程中,默认长度为1的数组是没有小数的 再归并合并数组的过程中, 合并前,左边是有序的,右边也是有序的 统计数量/如果左数小于右数,则代表需要产生一个小和, ((R - p2) + 1)代表的是右边数组中大于当前p1的有多少个数, 这个时候左边数组是有序的,右边数组是有序的

代码实现

private static int smallSum(int[] arr) {
    if (arr == null || arr.length < 2) {
        return 0;
    }
    return mergeSort(arr, 0, arr.length - 1);
}

private static int mergeSort(int[] arr, int L, int R) {
    if (L == R) {
        return 0;
    }
    int mid = L + ((R - L) >> 1);
    return mergeSort(arr, L, mid) +
            mergeSort(arr, mid + 1, R)
            + merge(arr, L, mid, R);
}


private static int merge(int[] arr, int L, int mid, int R) {
    int[] help = new int[(R - L) + 1];
    int p1 = L;
    int p2 = mid + 1;
    int i = 0;
    int res = 0;
    while (p1 <= mid && p2 <= R) {
        //如果左数小于右数,则代表需要产生一个小和,((R - p2) + 1)代表的是右边数组中大于当前p1的有多少个数,这个时候左边数组是有序的,右边数组是有序的
        res += arr[p1] < arr[p2] ? arr[p1] * ((R - p2) + 1) : 0;
        help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
    }
    //将左边还剩下的数放到arr里面去
    while (p1 <= mid) {
        help[i++] = arr[p1++];
    }
    //将右边还剩下的数放到arr里面去
    while (p2 <= R) {
        help[i++] = arr[p2++];
    }
    //排序
    for (int j = 0; j < help.length; j++) {
        arr[L + j] = help[j];
    }
    return res;
}