擴展歸併排序--小和問題/逆序對問題

問題描述

一個數列,其中一個數p,其左邊所有比p小的數的和,是數p的小和。
求這個數列所有數的小和之和。

例子:
[3, 1, 4, 5, 2]
3左邊比3小的數:
1左邊比1小的數:
4左邊比4小的數:3, 1
5左邊比5小的數:3, 1, 4
2左邊比2小的數:1
把這些數求和得到的就是小和: 13

解法

(1)暴力解法,遍歷。T=O(n^2)
(2)歸併排序

複習歸併排序:

a.首先劃分,一直劃分到不能劃分,即每個組都只有一個數值。
b.然後合併,合併的過程就是每個二劃分排序的過程。
c.在合併的時候,開闢一個輔助數組,其大小等於這兩個合併數列的大小。
d.設置兩個指針分別指向每個數列的首部,然後比較得到其中較小的值,並將這個值放入輔助數組中。然後取出小值的那個數列的指針可以繼續向前走,與另一個數列的指針所指向的值繼續比較
e.這樣比較完成後,如果兩個數列中有個數列的數值有剩餘,即其指針沒有走到末尾,則將這個數列直接賦到輔助數組末尾即可。
f.然後將輔助數組中的值拷貝回原數組中剛纔合併的那兩個數列的位置上。

思路:
在歸併排序的合併(combine)階段(即上面歸併排序的步驟d)進行小和問題的計算。
指針p1和p2指向兩個劃分後排好序的數組。p1指向的是左邊的數組(有位置信息),如果a[p1] < a[p2],(此時小和問題的兩個條件都滿足了:“左邊”,“小”),也就是說,p2指針後面的數也比a[p1]大(因爲是已經排好序的),一共有 (r-p2+1)個。(r表示數組最右端)。
所以,計算公式爲:

count += a[p1] < a[p2] ? (r - p2 + 1)*a[p1] : 0;

注:
計算小和問題,要乘a[p1]。因爲要求的不是比p小的個數,而是比p小的數的和。
如果要求的是個數(其實也就是擴展歸併排序的另一應用:逆序對問題(大小反過來的)) 則:

count += a[p1] < a[p2] ? (r - p2 + 1) : 0;

代碼

代碼直接copy了別人的,C/C++寫的,感覺不錯

#include <iostream>
#include <vector>
using namespace std;

/*
2017/11/12
利用歸併排序求小和
*/
#if 1
int merge(vector<int>&a, int l, int mid, int r)
{
    int count = 0;
    int p1 = l;
    int p2 = mid + 1;
    int i = 0;
    vector<int>help(r - l + 1);
    while (p1 <= mid && p2 <= r)
    {
        count += a[p1] < a[p2] ? (r - p2 + 1)*a[p1] : 0;
        help[i++] = a[p1] < a[p2] ? a[p1++] : a[p2++];
    }
    while (p1 <= mid)
        help[i++] = a[p1++];
    while (p2 <= r)
        help[i++] = a[p2++];
    for (i = 0; i < help.size(); i++)
        a[l + i] = help[i];
    return count;
}
int mergeSort(vector<int>&a, int l, int r)
{
    if (l == r)
        return 0;
    int mid = l + (r - l) / 2;
    return mergeSort(a, l, mid) + mergeSort(a, mid + 1, r) + merge(a, l, mid, r);
}
int SmallSum(vector<int>a)
{
    if (a.size() < 2)
        return 0;
    return mergeSort(a, 0, a.size() - 1);
}

void main()
{
    vector<int>a = { 7, 2, 14, 6, 14 };
    cout << SmallSum(a) << endl;
    system("pause");
}
#else
#endif

參考鏈接:
https://blog.csdn.net/zhzh402/article/details/80266663
https://blog.csdn.net/liuxiao214/article/details/78530993
https://blog.csdn.net/m0_37323771/article/details/79842263

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章