题目描述
Description
有一个由N个实数构成的数组,如果一对元素A[i]和A[j]是倒序的,即i<j但是A[i]>A[j]则称它们是一个倒置,设计一个计算该数组中所有倒置数量的算法。要求算法复杂度为O(nlogn)
Input
输入有多行,第一行整数T表示为测试用例个数,后面是T个测试用例,每一个用例包括两行,第一行的一个整数是元素个数,第二行为用空格隔开的数组值。
Output
输出每一个用例的倒置个数,一行表示一个用例。
Sample Input 1
1
8
8 3 2 9 7 1 5 4
Sample Output 1
17
思路主要是在归并排序上做一个小的修改,降低蛮力法的时间复杂度,达到O(nlogn)。在合并过程中右边序列发现有一个值比左边序列小,那么左边序列从该值开始到mid的数,都和右边这个数构成逆序对(因为左右序列都是有序的)。
package LeetCode_19_12;
import java.util.Arrays;
public class 倒置个数191209 {
int count = 0;
public void mergesort(int[] arr) {
sort(arr, 0, arr.length - 1);
}
public void sort(int[] arr, int L, int R) {
if (L == R) {
return;
}
int mid = L + ((R - L) >> 1);
sort(arr, L, mid);
sort(arr, mid + 1, R);
merge(arr, L, mid, R);
}
public void merge(int[] arr, int L, int mid, int R) {
int[] temp = new int[R - L + 1];
int i = 0;
int pa1 = L;
int pa2 = mid + 1;
while (pa1 <= mid && pa2 <= R) {
if (arr[pa1] < arr[pa2]) {
temp[i] = arr[pa1];
i++;
pa1++;
} else {
temp[i] = arr[pa2];
i++;
pa2++;
count += mid - pa1 + 1;
// 右边序列中只要有数比左边序列中数小,那么左边序列从这个数开始到结束的数都与右边序列构成逆序对。
// 因为每次归并的序列都输有序的。
}
}
// 两个序列比较然后将小的数插入temp,可能只比较了第一个数组的几个数另一个数组就到length
// 所以要把剩下的数也插入temp
while (pa1 <= mid) {// <=mid mid位置的数也要插入
temp[i++] = arr[pa1++];
}
while (pa2 <= R) {
temp[i++] = arr[pa2++];
}
// 一定要插入原数组
for (i = 0; i < temp.length; i++) {
arr[L + i] = temp[i];
}
}
public static void main(String[] args) {
int a[] = { 5, 4, 2, 1 };
int b[] = { 8, 3, 2, 9, 7, 1, 5, 4 };
倒置个数191209 p = new 倒置个数191209();
p.mergesort(b);
System.out.println(Arrays.toString(b));
System.out.println(p.count);
}
}