您的位置:首页 > 职场人生

【剑指offer】面试题36-数组中的逆序对

2017-01-21 14:54 246 查看

题目描述:

在数组中的两个数字如果前边的数字大于后边的数字,则这两个数值组成一个逆序对。输入一个数组,求出这个数组中逆序对的总数。

问题分析:

方法1:粗暴的办法。

具体实现方法:从数组中的第一个元素开始进行遍历,每次都去该元素之后的元素中查找多少个小于当前元素的值,然后进行统计。返回结果即可。

时间复杂度O(N*N),空间复杂度O(1)。

方法2:归并排序的思想。

由于上述方法的时间复杂度比较高,这里我们不妨采用空间换取时间的方法去统计逆序对的总数。

具体实现办法:

将数组划分成两个子数组,再将子数组分别划分成两个子数组,统计每个子数组内的逆序对个数,并将其归并排序,再统计两个子数组之间的逆序对个数,并进行归并排序。

为什么是要排序?因为计算了一个逆序对之后,就要打乱顺序,防止之后重复计算。

代码实现:

#include<iostream>
using namespace std;
//数组中的逆序对
long long GetMergePairsBetween(int* arr,int* copy,int start,int mid,int end)
{
//合并两个子数组,并计算逆序对个数
int final1 = mid;//第一个数组的最后一位
int final2 = end;//第二个数组的最后一位
int index = end;//辅助数组的最后一位
long long count = 0;
while(final1 >= start && final2 >= mid+1)//两个数组都没有处理完
{
if(arr[final1] > arr[final2])
{
//如果第一个数组的元素大于第二个数组的任何元素,
//则第一个数组的元素一定大于第个数组中final2之前的所有元素
count += (final2 - mid);
//将final1处的元素拷贝至copy数组
//index和final1都向前移动
copy[index--] = arr[final1--];
}
else
{
//第一个数组的元素小于第二个数组的元素
//第二个数组的元素拷贝至copy数组
//并将index和final2前移
copy[index--] = arr[final2--];
}
}
while(final1 >= start)//第一个数组的元素没有处理完
{
copy[index--] = arr[final1--];
}
while(final2 >= mid + 1)//第一个数组的元素没有处理完
{
copy[index--] = arr[final2--];
}
for(int i = end; i > index;i--)
arr[i] = copy[i];
return count;
}
long long GetMergePairs(int* arr,int* copy,int start,int end)
{
long long ret = 0;
if(start < end)
{
int mid = start + ((end - start)>>1);
ret += GetMergePairs(arr,copy,start,mid);
ret += GetMergePairs(arr,copy,mid+1,end);
ret += GetMergePairsBetween(arr,copy,start,mid,end);
}
return ret;
}
long long GetTotalPairs(int arr[],int n)
{
if(arr == NULL || n < 2)
return 0;
int* copy = new int
;
long long sum = GetMergePairs(arr,copy,0,n-1);
delete[] copy;
return sum;
}
int main()
{
int arr[] = {7,5,6,4};
int ret = GetTotalPairs(arr,sizeof(arr)/sizeof(arr[0]));
cout<<ret<<endl;
system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息