算法设计课作业系列5——Reverse Pairs

算法设计课作业系列(5)

Reverse Pairs

题目展示

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.

解题过程

解题思路

既然归类在分治的大类里面,就自然而然要去想怎么用分治的思想去完成,可以看到题目要求是i < j and nums[i] > 2*nums[j],因此,我们可以将一个数组划分成左右两部分,分别求出答案,而当分成只有一个数的时候,自然而然就是0咯,返回就好。在得到分出的两部分的结果之后,我们就想知道左右两部分之间会不会存在符合条件的结果呢?这时候如果左右两个子序列是排序好的,我们的整个过程就会方便很多,因此,我们在求出满足条件的数目之后,还需要对子序列进行归并排序,从而方便之后的操作,至于排序之后为什么两个子序列之间的比较的时间复杂度为线性的,就请自行思考或根据代码去推断或评论区评论啦~我们总结出以下算法流程:
1. 检测序列长度是否为1,若是,则返回0,不是,则继续划分成两个子序列
2. 得到左右子序列值之后,求出两个序列间是否存在满足调节的数对
3. 归并排序(因为两个序列都已经是排好序的,我的代码用了自带的sort函数来偷懒的)
4. 返回当前序列满足的值(子序列+两个序列间)

时间复杂度

T(n) = 2T(n/2) + O(n)

每个序列划分成两个子序列,归并操作和查找子序列间的数对操作都是线性时间
则a=2,b=2,d=1
所以由大师定理,时间复杂度为O(nlogn),所以和O(n^2)比起来,应该是优化了吧~

源代码

class Solution {
public:
    int reversePairs(vector<int>& nums) {
        return reversePairs(nums, 0, nums.size());
    }

    int reversePairs(vector<int>& nums, int begin, int end) {
        if (end - begin <= 1) {
            return 0;
        }
        int left = reversePairs(nums, begin, begin + (end - begin) / 2);
        int right = reversePairs(nums, begin + (end - begin) / 2, end);
        int cnt = 0;
        int num = left + right;
        for (int i = begin; i < begin + (end - begin) / 2; i++) {
            for (int j = begin + (end - begin) / 2 + cnt; j < end; j++) {
                if ((long)nums[i] > (2 * (long)nums[j])) {
                    cnt++;
                } else {
                    break;
                }
            }
            num += cnt;
        }

        sort(nums.begin() + begin, nums.begin() + end);

        return num;
    }
};
点赞