在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。给你一个数组,求出这个数组中逆序对的总数。
概括:如果a[i] > a[j] 且 i < j, a[i] 和 a[j] 构成一个逆序对。
样例
序列 [2, 4, 1, 3, 5] 中,有 3 个逆序对 (2, 1), (4, 1), (4, 3),则返回 3 。
代码
- 暴力法
public class Solution {
/**
* @param A: an array
* @return: total of reverse pairs
*/
public long reversePairs(int[] A) {
if (A == null || A.length == 0) {
return 0;
}
int result = 0;
for (int i = 0; i < A.length - 1; i++) {
for (int j = i+1; j < A.length; j++) {
if (A[i] > A[j]) {
result++;
}
}
}
return result;
}
}
- 归并排序
public class Solution {
/**
* @param A an array
* @return total of reverse pairs
*/
public long reversePairs(int[] A) {
return mergeSort(A, 0, A.length - 1);
}
private int mergeSort(int[] A, int start, int end) {
if (start >= end) {
return 0;
}
int mid = start + (end - start) / 2;
int sum = 0;
sum += mergeSort(A, start, mid);
sum += mergeSort(A, mid+1, end);
sum += merge(A, start, mid, end);
return sum;
}
private int merge(int[] A, int start, int mid, int end) {
// 此处如果写成 int[] temp = new int[A.length] 就比较耗费时间和空间
int[] temp = new int[end - start + 1];
int leftIndex = start;
int rightIndex = mid + 1;
// temp 数组的 index 要从 0 开始,如果写成等于 start,
// 当 start 不等于 0 就会出现越界错误
int index = 0;
int sum = 0;
while (leftIndex <= mid && rightIndex <= end) {
// 左指针指向的值小于等于右指针指向的值则不构成逆序对
if (A[leftIndex] <= A[rightIndex]) {
temp[index++] = A[leftIndex++];
} else {
temp[index++] = A[rightIndex++];
// 右指针指向的值小于左指针指向的值时,对于当前右指针指向的值
// 从当前左指针开始到 mid位置所有数都可以和右指针指向值构成逆序对
sum += mid - leftIndex + 1;
}
}
while (leftIndex <= mid) {
temp[index++] = A[leftIndex++];
}
while (rightIndex <= end) {
temp[index++] = A[rightIndex++];
}
for (int i = 0; i < temp.length; i++) {
// 此处是 i+start
A[i + start] = temp[i];
}
return sum;
}
}
网友评论