数组中的逆序对
在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。
输入一个数组,求出这个数组中的逆序对的总数。
样例
输入:[1,2,3,4,5,6,0]
输出:6
思路:
如果用双层循环暴力做,算法复杂度是o(n^2) 肯定是不对的
我们想到用排序算法做,既能遍历到逆序对,又能不改变原数组逆序对的前后位置,所以用归并排序做
假如[1,2,3,4,5,6,0]
归并排序:切分 也许不严谨但是得到了[1,2,3,4] , [0,5,6] 这两个数组,正常的归并就是将他们合并为一个数组,小的在前大的不动,由于0是后面那个数组的最小值,如果前面的第一个数1都要比0大,代表2,3,4不用比较了,肯定比0大,返回 前面第一次比第二个数组数大的index到第一个数组的边界(mid)的容量,就是这个部分的逆序对个数,利用二分递归如此反复,由于归并用了分治与归并,没有重复的子问题,所以这个逆序对不可能重复
public class Solution {
int res = 0;
public int inversePairs(int[] nums) {
mergeSort(nums, 0, nums.length - 1);
return res;
}
public void merge(int num[], int l, int r) {//归并
int temp[] = new int[r + 1];
int m = (l + r) / 2;
int i = l, j = m + 1, k = l;
while (i <= m && j <= r) {
if (num[i] < num[j]) {
temp[k++] = num[i];
i++;
} else {
res = res + m - i + 1;
temp[k++] = num[j];
j++;
}
}
while (i <= m) {
temp[k++] = num[i];
i++;
}
while (j <= r) {
temp[k++] = num[j];
j++;
}
for (int o = l; o <= r; o++) {
num[o] = temp[o];
}
}
public void mergeSort(int num[], int start, int end) {//分治
if (start == end) {//递归出口
return;
}
int mid = (start + end) / 2;
mergeSort(num, start, mid);
mergeSort(num, mid + 1, end);
merge(num, start, end);
}
public static void main(String[] args) {
int a[] = {1, 2, 3, 4, 5, 6, 0};
System.out.println(new D1().inversePairs(a));
}
}
6