问题描述:
给定一个数值a,如果a[i]>a[j](i<j),那么a[i]与a[j]被称为一个反序,例如,给定数组{1,5,3,2,6},共有(5,3)、(5,2)和(3,2)三个反序对。
方法一:
暴力法,遍历数组并与其后一个数字比较。时间复杂度:O(n^2)。
方法一代码如下:
package com.haobi;
public class Test30 {
public static void main(String[] args) {
int[] array = {1,5,3,2,6};
System.out.println(reverseCount(array));
}
public static int reverseCount(int[] a) {
int count = 0;
int len = a.length;
for(int i=0;i<len;i++) {
for(int j=i+1;j<len;j++) {
if(a[i]>a[j]) {
count++;
}
}
}
return count;
}
}
程序输出结果如下:
3
方法二:
分治归并法。参考归并排序方法,在归并排序的基础上额外使用一个计数器来记录逆序对的个数。时间复杂度:O(nlogn)。
方法二代码如下:
package com.haobi;
public class Test31 {
public static int reverseCount = 0;
public static void main(String[] args) {
int[] array = {1,5,3,2,6};
merge_sort(array, 0, array.length-1);
System.out.println(reverseCount);
}
public static void merge_sort(int[] a, int begin, int end) {
if(begin < end) {
int mid = begin+(end-begin)/2;
merge_sort(a, begin, mid);
merge_sort(a, mid+1, end);
merge(a, begin, mid, end);
}
}
public static void merge(int[] a, int begin, int mid, int end) {
int i,j,k,n1,n2;
n1 = mid-begin+1;//前半段的长度
n2 = end-mid;//后半段的长度
int[] L = new int[n1];
int[] R = new int[n2];
//前半段开始遍历并赋值
for(i=0,k=begin;i<n1;i++,k++) {
L[i] = a[k];
}
//后半段开始遍历
for(i=0,k=mid+1;i<n2;i++,k++) {
R[i] = a[k];
}
//归并排序操作
for(k=begin,i=0,j=0;i<n1&&j<n2;k++) {
if(L[i]<R[j]) {
a[k] = L[i++];
}else {
//统计逆序对个数
//reverseCount += mid-k+1;//?
reverseCount += n1-i;
a[k] = R[j++];
}
}
if(i<n1) {
for(j=i;j<n1;j++,k++) {
a[k] = L[j];
}
}
if(j<n2) {
for(i=j;i<n2;i++,k++) {
a[k] = R[i];
}
}
}
}
程序输出结果如下:
3