求数组中的逆序对的个数:在数组a中如果a[i]>a[j].且i<j则<i,j>称为一个逆序数对,例如数组是7,5 ,6 ,4 则逆序对共有 7,5 7,6 7,4 5,4 6,4 五个逆序对,刚开始的时候没有思路,看了看解答之后发现,还是采用分治的思想,类似于用归并算法实现,
空间复杂度为n,需要一个额外的数组来存储,时间复杂度为log2n(2是下标了,懒得打公式了)。具体的图解可看一下何海涛里面的图示。
记录一下我的代码吧,
//这个程序是求数组中的逆序对的
//剑指offer一书中的36题
#include<iostream>
using namespace std;
int b[100];
int n;
int Countreversion(int a[], int begin, int end)
{
if(end == (begin+1))
{
if( a[begin] > a[end])
{
int t=a[begin];
a[begin] = a[end];
a[end] = t;
return 1;
}
else
{
return 0;
}
}
else if( begin ==end)
return 0;
else if( end>(begin+1))
{
int mid = (begin+end)/2;
int left = Countreversion (a,begin,mid); cout << "begin is " <<begin << " mid is "<< mid <<endl;cout << "left is" << left<<endl;
cout << "The elment in a is : ";
for(int k=0; k<n; k++)
cout<<a[k]<<" ";
cout <<endl;
int right = Countreversion (a, mid+1, end); cout << " mid+1 is " <<mid+1 <<" end is " <<end <<endl;cout << " right is " <<right <<endl;
cout << "The elment in a is : ";
for(int k=0; k<n; k++)
cout <<a[k]<<" ";
cout <<endl;
int p=mid, q=end;
int current =end;
int number =left+right;
int next_q=end; //next_q 求的是下一次判断时q的起始位置,比如 左边是6,7,右边是 5,9 ,则下次从5开始,因为7<9了,
while(p >=begin)
{
q = next_q;
while( q>=(mid+1) && a[p] <=a[q])
{
b[current--] = a[q];
q--;
}
if( q>=(mid+1) && a[p]>a[q])
{
next_q = q;
b[current--] = a[p];
number+= q-(mid+1)+1;
p--;
}
else if( q<(mid+1))
{
while( p>=begin)
{
b[current--]=a[p];
p--;
}
}
if(p<begin && q>=(mid+1))// 这部分要注意,是处理左数组已经全部都复制到临时数组里了,但是右数组还有剩余
{//最简单的情况比如 左数组 6 ,7 右数组 3,4
//临时数组里会是6,7,6,7 ,也就是右数组还没放到临时数组中,则放进去为3,4,6,7
//之前程序出错,前面的都对,唯独忘记处理这种情况了。
while(q>=(mid+1))
{
b[current--] = a[q];
q--;
}
}
}
for(int i=begin ; i<=end; i++)
a[i]=b[i];
return number;
}
}
int main()
{
int a[100];
cin >>n;
for(int i=0; i<n; i++)
{
cin >>a[i];
b[i]=a[i];
}
for(int k=0; k<n; k++)
cout << " a is " <<a[k]<<" ";
cout <<endl;
cout << "The final result is " << Countreversion(a,0,n-1)<<endl;
return 1;
}
提供几组测试数据:
n=7 a: 6 7 4 3 5 1 2 结果为17
n=7 a:1 2 3 4 5 6 7 结果为0
n=7 a:7 6 5 4 3 2 1 结果为21