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