493. 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.
方法1: merge sort
grandyang:https://www.cnblogs.com/grandyang/p/6657956.html
思路:
参见327. Count of Range Sum。同为妙用merge sort。
利用递归的思想,首先统计两边各有多少reverse pairs,然后再统计两段连起来会增加多少。那么如何才能将第二步用小于O(n^2)的方法算出来呢?可以用双指针来遍历两边,对于每一个左边的数字nums[i], 我们找到右边和它reverse的那个最大值的右边一个,也就是第一个终于满足 nums[i] <= 2 * nums[j] 的值,那么如果我们知道前面的都是有序的,而且都比nums[j]小,那么可以一次性累加 j - mid这么多pair。而对于下一个i,在找属于它的 j 时只可能在更右边,没有必要回溯,这也是排序才能保证的。所以排序可以保证我们用O(N)的时间找出merge步骤中的reverse pair,因而得到O(nlogn)的算法。而比较的过程仅仅是和merge sort采用了不一样的不等式,可以用一个cache来完成,或者用内置的inplace_merger(begin() + left, begin() + mid + 1, begin() + right + 1)。
Complexity
Time complexity: O(n logn)
Space complexity: O(log n)
易错点:(无穷无尽)
- base case是什么:当区间内只剩下一个数字的时候,是不可能有reverse pair的,返回值是0。而这个时候对应的条件是right <= left。
- mid应该归谁:在二分法中mid的极端条件是和left重合的,发生在left + 1 = right时。一般情况下没毛病,但是这里我们要比较左右的pair,就必须正确划分mid此时的归属。只有当mid在left的范围内时,才能启动两个元素的base case comparison。
- 右半边遍历时要找什么:第一个违反了 nums[i] / 2.0 > nums[j]的j,那么满足条件的pair数量是j - (mid + 1),因为区间为[mid + 1, j)。而这样做就要求 j 的遍历范围 <= right而不是< right。
- 注意上面这个判断句必须是 / 2.0,否则overflow。
- 最后可以采用sort或者inplace_merge来sort,后者快一点。sort的指针是左闭右开,inplace_merge的两段区间划分也是左闭右开,[left, middle), [middle, right),所以mid 和 right 这两个参数使用时都应该 + 1。
class Solution {
public:
int reversePairs(vector<int>& nums) {
return pairHelper(nums, 0, nums.size() - 1);
}
int pairHelper(vector<int> & nums, int left, int right) {
if (right - left <= 0) return 0;
int mid = left + (right - left) / 2;
int res = pairHelper(nums, left, mid) + pairHelper(nums, mid + 1, right);
//vector<int> cache(right - left + 1, 0);
for (int i = left, j = mid + 1; i <= mid; i++) {
while (j <= right && nums[i] / 2.0 > nums[j]) j++;
res += j - (mid + 1);
}
//sort(nums.begin() + left, nums.begin() + right + 1);
inplace_merge(nums.begin() + left, nums.begin() + mid + 1, nums.begin() + right + 1);
return res;
}
};
方法2:BIT
discussion:https://www.cnblogs.com/grandyang/p/6657956.html
思路: