[2018-09-09] [LeetCode-Week1] 493. Reverse Pairs 分治

https://leetcode.com/problems/reverse-pairs/description/


Given an array nums, we call (i, j) an important reverse pair if i < j and nums[i] > 2*nums[j].

You need to return the number of important reverse pairs in the given array.

Example1:

Input: [1,3,2,3,1]
Output: 2
Example2:

Input: [2,4,3,5,1]
Output: 3
Note:
The length of the given array will not exceed 50,000.
All the numbers in the input array are in the range of 32-bit integer.


  1. 首先对于规模为 n 的问题,将数组分为左右两块 (l, m) 和 (m+1, r),递归计算每块的逆序对数量,再加上横跨两边的逆序对的数量即可。
  2. 对于横跨两边的逆序对的数量,暴力求解为 O(n^2)。显然不满足要求。
  3. 由于是求逆序对,我们可以将左右两边分别排序,对于每个左边的 nums[i], 求得右边满足逆序的最大的 nums[j], 则 i 位置对应的横跨逆序对一共有 j-(m+1) 个。此时只需要 j 扫一遍,复杂度为 O(n)。
  4. 发现此时要求左右两边分别排好序,则考虑归并排序,即可达到排序目的。
  5. 注意数据中存在很大的整数,判定 nums[j] * 2 会溢出,需要处理为 double 或者 longlong。

class Solution {
public:
    void mergeSort(int l, int r, vector& nums) {
        int array[r-l+1];
    
        int m = (l + r) / 2;
    
        int i = l;
        int j = m+1;
    
        int p = 0;
        while (i <= m && j <= r) {
            if (nums[i] <= nums[j]) array[p++] = nums[i++];
            else array[p++] = nums[j++];
        }
        while (i <= m) array[p++] = nums[i++];
        while (j <= r) array[p++] = nums[j++];
    
        for (int t = 0; t < p; t++) {
            nums[l + t] = array[t];   
        }
    }

    int divideCalc(int l, int r, vector& nums) {
        if (l >= r) return 0;
    
        int m = (l + r) / 2;
        int ans = divideCalc(l, m, nums) + divideCalc(m+1, r, nums);
    
        int j = m+1;
        for (int i = l; i <= m; i++) {
            double ni = nums[i] / 2.0;
            while (j <= r && ni > nums[j]) {
                j++;  
        }
        ans += j - (m + 1);
    }
        mergeSort(l, r, nums);
    
        return ans;
    }

    int reversePairs(vector& nums) {
        return divideCalc(0, nums.size()-1, nums);
    }
};

你可能感兴趣的:([2018-09-09] [LeetCode-Week1] 493. Reverse Pairs 分治)