1、题目
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:
输入: [7,5,6,4]
输出: 5
限制:
0 <= 数组长度 <= 50000
2、解题思路
(1)解决思路一:暴力破解(双循环,临时变量来存储逆序对的个数),时间复杂度o(n)
(2)解决思路二:归并排序;
(1)复制出来一个数组;(因为后续会对参数数组进行排序)
(2) 对数组拆分,拆分,再拆分;一直拆分到每组两个元素
(3)计算每组里面多少个逆序对
(4)合并相邻的两个分组(合并的时候进行计算 左边分组逆序对,右边分组逆序对,合并后逆序对)
(5)累加所有的逆序对个数即为整个数组的逆序对个数;
3、java代码
class Solution {
public int reversePairs(int[] nums) {
if (nums == null || nums.length < 2) {
return 0;
}
// 为了不改变原数组,这里先将原数组拷贝一份
int[] copy = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
copy[i] = nums[i];
}
//tmp用来存储排序后的数组
int[] tmp=new int[nums.length];
return reversePairs(nums,0,nums.length-1,tmp);
}
//拆分->拆分->合并->合并
public int reversePairs(int[] nums, int left, int right, int[] tmp) {
if (left >= right) {
return 0;
}
//1、求出来中间值
int mid = (left + right) / 2;
//2、持续调用拆分合并的过程;先拆左边,再拆右边,然后再合并
int leftvalue = reversePairs(nums, left, mid, tmp);
int rightvalue = reversePairs(nums, mid+1, right, tmp);
int mergevalue = this.merge_Array(nums, left, mid, right, tmp);
return leftvalue + rightvalue + mergevalue;
}
//合并的方法
private int merge_Array(int[] nums, int left, int mid, int right, int[] tmp) {
for (int i = left; i <= right; i++) {
tmp[i] = nums[i];
}
//定位两个指针来遍历需要合并的两个数据区间;tmp作为排序后的数组,nums作为排序前作为对照
int i = left;
int j = mid + 1;
int count = 0;
for (int k = left; k <= right; k++) { //遍历整个数据区间
if (i == mid + 1) { //左边到头了,填充右边的元素
nums[k]=tmp[j++];
} else if (j == right + 1) { //右边到头了,填充左边的元素
nums[k]=tmp[i++];
} else if(tmp[i]<=tmp[j]){ //左边的小于等于右边,则放左边的
nums[k]=tmp[i++];
} else{ //右边的小于左边,则放右边的
nums[k]=tmp[j++];
count+=mid+1-i;
}
}
return count;
//返回逆序对
}
}