题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
输入描述:
题目保证输入的数组中没有的相同的数字
数据范围:
对于%50的数据,size<=10^4
对于%75的数据,size<=10^5
对于%100的数据,size<=2*10^5
示例1
输入
1,2,3,4,5,6,7,0
输出
7
思路1:直接就是想数组两两进行比较,累加来求出逆序对的数目。但是这个算法的时间复杂度是O(n^2).
class Solution {
public:
int InversePairs(vector<int> data) {
if(data.empty()||data.size()==1)//数组为空或者只有一个数
{
return 0;
}
int count = 0;//逆序对的个数
int len = data.size();
for(int i=0;i<len-1;i++)//从第一个开始到倒数第二个
{
for(int j=i+1;j<len;j++)
{
if(data[i]>data[j])
{
count++;
}
}
}
int res = count%1000000007;
return res;
}
};
思路2:
利用了归并排序的算法的一种思想,现将数组分成子数组,先统计出子数组中的逆序对的个数,然后将子数组排序(为了避免后续统计子数组之间的逆序对数时重复统计)再统计子数组之间逆序对数。不断统计不断归并。
1、先将长度为4的数组一分为二为长度为2的数组
2、将长度为2的数组分为长度为1的数组
3、将长度为1的数组归并、排序、统计逆序对
4、将长度为2的数组统计逆序对归并排序,统计逆序对。
在进行长度为1的数组的归并时,有逆序对<8,6>,<7,5>,然后排序
在进行长度为2的数组的归并时,两个数组之间的逆序对有<8,7>,<8,5>,<6,5>,之后合并排序。
具体进行数组间的逆序统计是这样的:以上述数组长度为2的归并统计为例:
(1)先设置两个指针分别指向两个数组的末尾,比较两个指针指向的大小,若*p1>p2,,逆序对的个数是第二个数组剩余的元素个数,将第一个数组的p1指向的移入到辅助数组中,p1向前移动。
(2)若p1<*p2,则是将p2所指向的移入到辅助数组中,p2向前移动,继续比较,知道比较完成,下面我们看一下具体的例子
过程大致就是这样的
实现:C++
class Solution {
public:
int InversePairs(vector<int> data) {
int len = data.size();
if(len==0)
{
return 0;
}
int count = merge(data,0,len-1);
return count%1000000007;
}
int merge(vector<int>&data,int low,int high)//相当于递归排序的过程,顺带统计逆序对数
{
if(high<=low)//递归终止条件
{
return 0;
}
int mid = (low+high)/2;
int lcount = merge(data,low,mid);//左半边逆序对数
int rcount = merge(data,mid+1,high);
vector<int> temp=data;
int forid=mid,backid=high,tempid=high;//分别指的是前半部分的下标,后半部分的下标,辅助数组的下标
int becount=0;//两个数组之间的逆序对的个数
while(forid>=low&&backid>=mid+1)
{
if(data[forid]>data[backid])//存在逆序数对
{
temp[tempid--]=data[forid--];
becount += backid-mid;
}
else{//不存在
temp[tempid--]=data[backid--];
}
}
while(forid>=low)
{
temp[tempid--]=data[forid--];
}
while(backid>=mid+1)
{
temp[tempid--]=data[backid--];
}
for(int i=low;i<=high;i++)
{
data[i]=temp[i];
}
return (lcount+rcount+becount);
}
};
不知道为啥,两种的运行时间当数据很多时,超过了要求,不过算法是对的