解法1:暴力法(超时)
思想:
每次固定一个节点,遍历其后的节点
复杂度:
●时间:O(N^2)
●空间:O(1)
代码:
class Solution {
public:
int reversePairs(vector<int>& nums) {
if(nums.size() <= 1)
return 0;
int res = 0;
for(int i = 0; i < nums.size() - 1; ++i)
for(int j = i + 1; j < nums.size(); ++j)
if(nums[i] > nums[j])
res++;
return res;
}
};
解法2:归并排序
思想:
在归并排序中加入求逆序对。
求一个区间的逆序对 = 左区间内部逆序对 + 右区间内部逆序对 + 跨左右区间的逆序对
复杂度:
和归并排序的复杂度一样
●时间:O(NlogN)
●空间:O(N),额外数组
代码:
class Solution {
private:
// 不能在这里定义,因为vector<int>tmp(5, 0)也可以看做是声明一个返回vector<int>的tmp函数
vector<int>tmp;
public:
int reversePairs(vector<int>& nums) {
// 在函数内定义tmp
tmp.assign(nums.size(), 0);
return merge_sort(nums, 0, nums.size() - 1);
}
// 返回逆序对总数的归并排序
int merge_sort(vector<int>& nums, int left, int right){
if(left >= right)
return 0;
int mid = left + (right - left) / 2;
// 此时左右两个区间均排序完毕,且ans为左区间和右区间的逆序对总数(左内部 + 右内部,没加上跨区间的逆序对),再加上两个区间各出一个数的逆序对数就得到最终结果
int ans = merge_sort(nums, left, mid) + merge_sort(nums, mid + 1, right);
int left_index = left, right_index = mid + 1;
int tmp_index = 0;
// 下面三个while就是一般的归并排序,不同的是第一个while的else
while(left_index <= mid && right_index <= right){
if(nums[left_index] <= nums[right_index])
tmp[tmp_index++] = nums[left_index++];
else{
//从右边拿数到tmp,说明左边数组剩余的数都大于此数,并且位置在此数的左边,所以左边剩余多少数就构成多少逆序对
ans += mid - left_index + 1;
tmp[tmp_index++] = nums[right_index++];
}
}
while(left_index <= mid){
tmp[tmp_index++] = nums[left_index++];
}
while(right_index <= right){
tmp[tmp_index++] = nums[right_index++];
}
//从临时数组赋值到nums中,排序需要改变nums数组
tmp_index = 0;
for(int i = left; i <= right; ++i){
nums[i] = tmp[tmp_index++];
}
return ans;
}
};