493. Reverse Pairs
题目链接:493. Reverse Pairs
题意
找出给定数组中重要逆序的对数,重要逆序定义如下:i
解法
最简单的方法就是暴力穷举,对于每个位置i都遍历一遍前面的元素,看看有没有构成逆序的元素,但是这种方法肯定是会超时的。
第二种方法是用二叉搜索树,定义树节点为拥有字段value和count的类,count是树中value大于本节点的节点数目。定义insert方法将整形值插入树中,search方法搜索树中value大于参数的节点的数量。每到一个位置i处,将i前面的元素都插入二叉搜索树,然后搜索树中value值大于等于2*nums[i]+1的节点数。理想情况下二叉搜索树能将搜索复杂度降低到O(NlogN),但是在某些情况下二叉树会退化成为链表,所以还得增加自旋保持树平衡。
第三种方法是使用类似于归并排序的算法,每次将参数数组均分成两半,分别递归处理,用变量count存储分割后的小数组返回的结果,然后在未分割的大数组(起始位置为l,终止位置为r)中,从l到中间位置mid以及从位置mid+1到r两个区域都已经分别被排序,这时用i遍历左边的半个数组,用j遍历右边的半个数组,对于每个i,只要i,j位置上的元素能够构成重要逆序的话,j就自增,对于每一个i,count的增量是j离起始位置mid+1的距离,也就是说,如果前一轮i循环的时候j已经自增到r+1,本轮i循环j不再增加,count还是要加上j-(mid+1)这个增量,因为正如前面说的,区间[l,mid]已经排好了序。
代码
class Solution {
public:
int reversePairs(vector<int>& nums) {
return mergeCount(nums, 0, nums.size() - 1);
}
int mergeCount(vector<int> &nums, int l, int r) {
if (l >= r)return 0;
int count = 0;
int mid = (l + r) / 2;
count += mergeCount(nums, l, mid) + mergeCount(nums, mid + 1, r);//
for (int i = l, j = mid + 1; i <= mid; ++i) {
while (j <= r && (nums[i] + 0.0) / 2 > nums[j])
++j;
count += j - mid - 1;//注意,这里就算前面的nums[i]使j增大到r+1,本次循环中 j 没有自增
//count仍然需要加上j-mid-1,因为每一次l到mid以及mid+1到r这两个大区间内部都是排好序的
}
sort(nums.begin() + l, nums.begin() + r + 1);
return count;
}
};
算法复杂度
算法复杂度为O(nlogn)。