逆序对
设 A 为一个有 n 个数字的有序集 (n>1),其中所有数字各不相同。
如果存在正整数 i, j 使得 1 ≤ i < j ≤ n 而且 A[i] > A[j],则 <A[i], A[j]> 这个有序对称为 A 的一个逆序对,也称作逆序数。
定义
对于一个包含N个非负整数的数组A[1..n],如果有i < j,且A[ i ]>A[ j ],则称(A[ i] ,A[ j] )为数组A中的一个逆序对。
例如,数组(3,1,4,5,2)的逆序对有(3,1),(3,2),(4,2),(5,2),共4个。
问题描述
给定一 个 数组 ,求该 数组中包含多少个逆序对。
求解方法
方法一:最原始的方法,利用两重循环进行枚举。该算法的时间复杂度为O(n^2)。
C++代码如下:
int count_inversion(int *a, int N)
{
int count = 0;
int i, j;
for(i=0; i<N-1; i++)
for(j=i+1; j<N; j++)
if(a[i]>a[j])
count++;
return count;
}
方法二:利用归并排序的思想求解逆序对的个数,这是解决该问题的一种较为高效的算法。该算法的时间复杂度为O(nlogn)。
int inversion_count = 0; // 记录逆序对个数
int count = 0; // 记录顺序对个数
void merge(int *src, int *des, int start, int mid, int end)
{
int i = start, j = mid + 1;
int k = start;
while (i != mid + 1 && j != end + 1)
{
if (src[i] < src[j])
{
des[k++] = src[i++];
count += end - j + 1; // 统计“顺序对”个数
}
else
{
des[k++] = src[j++];
inversion_count += mid - i + 1; // 统计“逆序对”个数
}
}
while (i != mid + 1) des[k++] = src[i++];
while (j != end + 1) des[k++] = src[j++];
for (i = start; i != end + 1; ++i)
src[i] = des[i];
}
void mergeSort(int *src, int *des, int start, int end)
{
int mid;
if (start < end)
{
mid = (start + end) >> 1;
mergeSort(src, des, start, mid);
mergeSort(src, des, mid + 1, end);
merge(src, des, start, mid, end);
}
}