程序员面试题——数组中的逆序对

程序员面试题——数组中的逆序对

1.题目
   在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。例如,有一个数组为Array[0..n] 其中有元素a[i],a[j].如果 当i<j时,a[i]>a[j],那么我们就称(a[i],a[j])为一个逆序对。在数组{7,5,6,4}中一共存在5对逆序对,分别是(7,6),(7,5),(7,4),(6,4),(5,4)。

2. 解题思路

      看到这样的题目,最简单的想法就是遍历每一个元素,让其与后面的元素对比,如果大于则count++,但是这样的时间复杂度是o(n2)。这题有更好的解决方法,时间复杂度只需要o(nlogn)。其实这道题目的思路跟归并排序差不多,求逆序对的过程就是一个求归并排序的过程,在求出逆序对以后,原数组变得有序,是通过归并排序得到的。

     (1)将数组分成两段,首先求段内的逆序对数量。

     (2)然后求段间的逆序对数量。

     (3)然后在求段间逆序对的时候,我们分为arry[start...mid]和arry[mid+1...end],然后设置两个指针ij分别指向两段数组的末尾元素,也就是i=mid,j=end。然后比较arry[i]和arry[j]。

         1. 如果arry[i]>arry[j],因为两段数组都是有序的,所以arry[i]>arry[mid+1...j],这些都是逆序对,我们统计出的逆序对为j-(mid+1)+1=j-mid。并且将大数arry[i]放入临时数组temp[]当中,i往前移动

         2. 如果arry[i]<arry[j],则将大数arry[j]放入temp[]中,j往前移。

     注:详细分析请参考《 剑指offer名企面试官精讲典型编程题》!!
3. 测试代码如下

#include<iostream>
using namespace std;
int InversePairsCore(int* data,int* copy,int start,int end);
int InversePairs(int* data,int length)
{
  if(data==NULL||length<0)
     return 0;
  int* copy=new int[length];
  for(int i=0;i<length;i++)
 copy[i]=data[i];
  int count=InversePairsCore(data,copy,0,length-1);
  delete[] copy;
  return count;
}


int InversePairsCore(int* data,int* copy,int start,int end)
{
  if(start==end)
  {
     copy[start]=data[start];  
return 0;
  }
  int length=(end-start)/2;
  int left=InversePairsCore(copy,data,start,start+length);
  int right=InversePairsCore(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[i];
  return left+right+count;
}


void main()
{
int array[]={1,3,7,8,2,4,6,5};
int len=sizeof(array)/sizeof(int);
cout<<InversePairs(array,len)<<endl;
system("pause");
}


参考来源:《剑指offer名企面试官精讲典型编程题》——何海涛

你可能感兴趣的:(程序员面试题——数组中的逆序对)