什么是逆序对儿?
逆序对儿的定义为:在一个数组中,有两个数满足数组的下标满足i < j 时arr[i] > arr[j], 这样的一对儿数字称之为逆序对儿,再 为了有助于理解,再简单举个例子吧,有一数组arr中有四个元素,分别为7,4,8,6,那么7和4、7和6、8和6都是这个数组的逆序对儿,那么这个数组的逆序对儿个数就为3。那如何来求解他们的逆序对儿个数呢,请看下面的思路分析。
思路分析
当 大家看到这个题的第一反应可能是使用穷举法,把数组所能够组成的对儿全部求解出来,然后进行判断,累加,这样求解的时间复杂度为O(n2),我们通过下面的例子来分析一下,有艺术组数组中的元素为7,5,6,2,我们可以采用分治的思想来求解,我们可以将这个数组拆分为两个长度为2的子数组,再把长度为2的子数组拆分为两个长度为1的子数组,{7}、{5}和{6}、{2},{7、5}和{6、2}都是逆序对儿,然后,我们再合并{7,5}和{6,2},再合并的同时统计逆序对儿的个数,由于我们已经统计了两个子数组内部的逆序对儿,所以我们应该对其进行排序,以免重复记录如下图分析:
通过上面的分析,大家应该会发现需找逆序对儿的过程很像归并排序,其实,在寻找逆序对儿个数的过程就是在归并排序的归并过程中对逆序对儿 进行统计即可。那么如何统计呢,思路如下图,还是使用上面的例子进行说明:
将{5、7}和{4,6}合并成一个数组并且统计逆序对儿的思路如下:P1指向的数字比P2指向的数字大, 那么P1指向的数字肯定比4 大,所以,逆序对儿+2,且将大的那个数字放入P3指向的位置,P1--,P3--,然后,然后,P1指向的数字比P2小,逆序对儿数不变,然后,将6放入数组中,P2--,再比较P1和P2指向的数字,逆序对儿数+1,将5放入数组中P3--,最后 再将4放入数组中。
代码实现
int InversePairCore(int *data,int *copy, int start, int end)
{
if(start == end)
{
copy[start] = data[start];
return 0;
}
int length = (end-start)/2;
int left = InversePairCore(copy,data,start,start+length);
int right = InversePairCore(copy,data,start+length+1,end);
int i = start + length;
int j = end;
int indexCopy = end;
int count = 0;
while(i >= start && j >= start+length+1)
{
if(data[i] > data[j])
{
copy[indexCopy--] = data[i--];
count += j - start -length;
}
else
{
copy[indexCopy--] = data[j--];
}
}
for(;i >= start;--i)
{
copy[indexCopy--] = data[i];
}
for(;j >= start+length+1;--j)
{
copy[indexCopy--] = data[j];
}
return left + right + count;
}
int InversePairs(int *data, int length)
{
if(data == NULL || length < 0)
{
return 0;
}
int *copy = (int *)malloc(sizeof(int) * length);
assert(copy != NULL);
int count = InversePairCore(data,copy,0,length-1);
printf("数组排序后的结果为:");
for(int i = 0;i < length;i++)
{
printf("%d ",copy[i]);
}
printf("\n");
free(copy);
return count;
}
O了