题目
解题思路
n 最大为50000,所以暴力解法(双层循环)一定会超时。
归并排序 分为划分阶段与合并阶段,其中,合并阶段也就是合并两个有序数组时,每当遇到 【左子数组当前元素大于右子数组当前元素】 ,【左子数组当前元素至末尾元素】 就与 【右子数组当前元素】 构成了若干 逆序对。
具体代码
class Solution {
int[] nums, tmp;
public int reversePairs(int[] nums) {
this.nums = nums;
tmp = new int[nums.length];//辅助数组,用于合并阶段暂存元素
return mergeSort(0, nums.length - 1);
}
private int mergeSort(int left, int right){
//划分阶段
if(left >= right)return 0;//划分终止
int m = (left + right) / 2;//中点
int res = mergeSort(left, m) + mergeSort(m + 1, right);//递归划分
//合并阶段
int i = left, j = m + 1;//i,j指向左右子数组的首元素
for(int k = left; k <= right; k++){//将数组nums[left,right]中的元素暂存到辅助数组
tmp[k] = nums[k];
}
for(int k = left; k <= right; k++){
if(i == m + 1)nums[k] = tmp[j++];//若左子数组已合并结束,添加右子数组当前元素并将j后移一位
//若右子数组已合并结束,或左子数组当前元素小于等于右子数组当前元素,添加左子数组当前元素并将i后移一位
else if(j == right + 1 || tmp[i] <= tmp[j])nums[k] = tmp[i++];
else{//否则左子数组当前元素大于右子数组当前元素
nums[k] = tmp[j++];//添加右子数组当前元素并将j后移一位
res += m - i + 1;//统计逆序对
}
}
return res;
}
}
复杂度分析
- 时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn),n 为数组长度。归并排序的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)
- 空间复杂度: O ( n ) O(n) O(n) 辅助数组 t m p tmp tmp 占用的额外空间为 O ( n ) O(n) O(n)