zoukankan      html  css  js  c++  java
  • 归并排序:小和问题

    归并排序:小和问题

    在一个数组中,每一个元素左边比当前元素值小的元素值累加起来,叫做这个数组的小和
    例如:[2, 3, 4, 1, 5]
    2 左边比 2 小的元素:无
    3 左边比 3 小的元素:2
    4 左边比 4 小的元素:2,3
    1 左边比 1 小的元素:无
    5 左边比 5 小的元素:2, 3, 4, 1
    小和small_sum = 2 + 2 + 3 + 2 + 3 + 4 + 1 = 17

    解法

    利用归并排序的性质,将数组二分,递归排序,在放入辅助数组的时候,由于左右两个数组都是排好序的,所以当右边有1个数大于左边某元素时,右边右面的数肯定大于该元素,只需将该元素乘以大于其元素个数,累加到sum上即可

    如数组[2, 3, 4, 0, 5, 6, 1, 8]

    递归调用归并排序,形成如下:

    ​ [2, 3, 4, 0] [5, 6, 1, 8]

    [2, 3] [4, 0] [5, 6] [1, 8]

    [2] [3] [4] [0] [5] [6] [1] [8]

    由于递归的特性,先对2和3进行排序,放入辅助数组时, 左边2小于右边3,由于右边3后面没有其他数了,所以sum+=2x1,2和3从小到大排序。然后计算4和0,4大于0,不累加,直接进行排序。而后计算[2, 3]和[0, 4],放入辅助数组时,左边第一位2大于右边第一位0,由于左边是从小到大排序的,2都比0大了,2后面的数字不可能比0小,所以直接将0放入辅助数组,指针指向4, 2比4小,但是4后面没有更多数字了,所以2累加到sum上,sum+=2x1,然后2放入辅助数组,左边指向3, 3小于4,累加上sum+=3x1,然后完成排序,产生[0, 2, 3, 4]。右边同理,最后[0, 2, 3, 4]和[1,5,6,8]进行排序, 左边0和右边1进行比较,0比1小,由于右边是从大到小排好序的,所以后面的数字都比0大,直接累加sum+=0*4;其他的元素同理;

    代码

    #include <stdio.h>
    
    int helperArr[10];
    
    int Merge(int arr[], int l, int mid, int r)
    {
        int i = l;
        int p1 = l;
        int p2 = mid + 1;
        int sum = 0;
        while (p1 <= mid && p2 <= r) {
            sum += arr[p1] < arr[p2] ? arr[p1] * (r - p2 + 1) : 0;
            helperArr[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
        }
        while (p1 <= mid) {
            helperArr[i++] = arr[p1++];
        }
        while (p2 <= r) {
            helperArr[i++] = arr[p2++];
        }
    
        for (; l <= r; l++) {
            arr[l] = helperArr[l];
        }
        return sum;
    }
    
    int MergeSort(int arr[], int l, int r)
    {
        if (l == r) {
            return 0;
        }
        int mid = l + ((r - l) >> 1); // =(l+r)/2 因为l+r有可能会溢出,所以改成减法的方式
        return MergeSort(arr, l, mid) + MergeSort(arr, mid + 1, r) + Merge(arr, l, mid, r);
    }
    
    int SmallSum(int arr[], int size)
    {
        if (arr == NULL || size < 2) {
            return 0;
        }
        return MergeSort(arr, 0, size - 1);
    }
    
    void PrintArr(int arr[], int size)
    {
        for (int i = 0; i < size; ++i) {
            printf("%d ", arr[i]);
        }
        printf("
    ");
    }
    
    int main()
    {
        int arr[10] = {6, 0, 5, 3, 15, 21, 13, 9, 12, 8};
        PrintArr(arr, 10);
        int ret = SmallSum(arr, 10);
        PrintArr(arr, 10);
        printf("小和是:%d", ret);
        return 0;
    }
    
  • 相关阅读:
    E
    D
    C
    B
    Python
    IDEA 设置资源目录
    光猫指示灯含义
    IO模型
    Linux 总目录
    Linux python 使用
  • 原文地址:https://www.cnblogs.com/causewang/p/12064308.html
Copyright © 2011-2022 走看看