LC493. 翻轉對-歸併排序

題目描述
在這裏插入圖片描述
思路: 利用歸併排序的思想當我們希望在數組中求出逆序對的數目時,我們可以使用歸併排序的方法。這道題中i < jnums[i] > 2 * nums[j]的要求與逆序對類似,因此我們也可以使用歸併排序的方法求出翻轉對的數目。

在歸併排序中,當我們歸併兩個子數組 nums[start .. mid]nums[mid + 1 .. end] 時,我們可以計算出對於前者中的每一個元素nums[i],後者中滿足 nums[i] > 2 * nums[j]j的數目。由於兩個子數組已經排好序,因此對於固定的 i,滿足條件的 j 的區間一定是從後者的左端點開始,並且隨着 i 的增加,j 區間的右端點不會減小。因此我們可以在 nums[mid + 1 .. end] 中維護一個指針 pos,表示對於當前的inums[mid + 1 .. pos] 的兩倍都小於 nums[i]。隨着 i 的增加,我們嘗試向右移動 pos使得更多的數滿足條件。

    int reversePairs(vector<int>& nums) {
        return mergersort(nums, 0, nums.size()-1);
    }
    int mergersort(vector<int>& nums, int s, int e)
    {
        if(s < e)
        {
            int mid = s + ((e - s) >> 1);
            int sum = mergersort(nums, s, mid) + mergersort(nums, mid+1, e);
            int j = mid + 1;
            for (int i = s; i <= mid; i++) {
                while (j <= e && nums[i] > nums[j] * 2LL)
                    j++;
                sum += j - (mid + 1);
            }

            merger(nums,s,mid,e);
            return sum;
        }
        return 0;
    }
    int merger(vector<int>& nums, int s, int m, int e)
    {
        int help[e-s+1];
        int r = m + 1;
        int l = s;
        int res = 0, i = 0;
        while(l <= m && r <= e)
        {
            help[i++] = nums[l] < nums[r] ? nums[l++] : nums[r++];
        }
        while(l <= m) help[i++] = nums[l++];
        while(r <= e) help[i++] = nums[r++];
        for(i = s; i <= e; i++)
        {
            nums[i] = help[i-s];
        }
        return res;
    }

時間複雜度:O(N log N)
空間複雜度:O(N)

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