算法设计课作业系列(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;
}
};