《劍指offer》——數組中的逆序對

以數組{7,5,6,4}爲例,
這裏寫圖片描述
1. 將數組中的每個元素看作是一個子數組,一邊將子數組排序(升序)後合併,一邊統計逆序對。
2. 對合並後的子數組重複第一步。
其中,統計逆序對的方法如下,:
這裏寫圖片描述
總結,
這裏寫圖片描述
時間複雜度爲O(n^logn),空間複雜度O(n)

參考歸併排序的代碼可以得到如下代碼:

/*合併子數組,並統計逆序對的個數*/
int merge(vector<int> &data, int lo, int mi, int hi, int num)
{
    int i = mi,//低位子數組的最大下標
        j = hi,//高位子數組的最大下標
        k = hi - lo;//輔助數組下標的最大值
    vector<int> temp;
    temp.resize(hi - lo + 1);//輔助數組的長度
    while(i >= lo && j >= mi + 1)
    {
        if(data[i] > data[j])//若存在逆序對
        {
            num += j - mi;//逆序對的個數
            temp[k--] = data[i--];
        }
        else//若不存在逆序對
        {
            temp[k--] = data[j--];
        }
    }
    while(i >= lo)//當高位子數組元素已經全部複製到輔助數組中時,將低位子數組剩下的元素複製到輔助數組中
        temp[k--] = data[i--];
    while(j >= mi + 1)//當低子數組元素已經全部複製到輔助數組中,將高位子數組剩下的元素複製到輔助數組中
        temp[k--] = data[j--];
    for(i = lo, k = 0; i <= hi; i++, k++)//用輔助數組中的元素更新原數組中的元素
        data[i] = temp[k];
    return num;//返回逆序對的個數
}

/*主程序*/
int InversePairs(vector<int> data) 
{
    int n = data.size();//數組長度
    if(data.empty())//若輸入空數組,返回0
        return 0;
    int size = 1;//第一次合併時,將每個元素看作一個子數組
    int lo, mi, hi;//指示下標
    int num = 0;//逆序對的個數
    while(size < n)//子數組的長度小於原數組長度時,循環統計逆序對的個數
    {
        lo = 0;//從下標爲0的元素開始
        while(lo + size < n)
        {
            mi = lo + size - 1;
            hi = mi + size;
            if(hi > n - 1)//若數組元素爲奇數個
                hi = n - 1;
            num = merge(data, lo, mi, hi, num);//合併子數組
            lo = hi + 1;//下次合併開始元素的下標
        }
        size = size >> 1;//子數組長度擴大2倍
    }
    return num;//返回逆序對的個數
}
發佈了82 篇原創文章 · 獲贊 6 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章