题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数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
思路
①首先明白什么是逆序对?就是在一个序列中,前面值大于后面值的这个序列,称为逆序对。
②两层for循环,即可求出该序列中的所有逆序对,但是时间复杂度太高O(n^2)
③有什么技巧呢?归并排序,归并排序先无限二分,然后合并,两个序列在合并的时候,统计逆序对,统计逆序对的时候也不需要全程比较,
【5 8 9】 和 【1 3 6 7】进行合并,每个子序列毫无疑问肯定是有序的,进行合并时
5>1,第一个序列,5后面的数都大于1,逆序对数=第一个序列最后一位-5的位置
5>3,同上
5<6,后移,没有逆序对
8>6,第一个序列,8后面的数都大于6,逆序对数=第一个序列最后一位-8的位置
8>7
end
代码
#include<stdio.h>
#include<vector>
#include<iostream>
using namespace std;
int tmp[200005];
int ans;
//需要修改vector数组的值,要用指针
void Merge(vector<int> *a,int l,int m,int r)
{
int i = l;
int j = m + 1;
int k = l;
while(i <= m && j <= r)
{
if((*a)[i] > (*a)[j])
{
tmp[k++] = (*a)[j++];
ans = (ans+m - i + 1)%1000000007;
}
else
{
tmp[k++] = (*a)[i++];
}
}
while(i <= m) tmp[k++] = (*a)[i++];
while(j <= r) tmp[k++] = (*a)[j++];
for(int i=l;i<=r;i++)
(*a)[i] = tmp[i];
}
void Merge_sort(vector<int> *data,int l,int r)
{
if(l < r)
{
int m = (l + r) >> 1;
Merge_sort(data,l,m);
Merge_sort(data,m+1,r);
Merge(data,l,m,r);
}
}
int InversePairs(vector<int> data) {
ans=0;
int n=data.size();
Merge_sort(&data,0,n-1);
return ans;
}
int main()
{
int a[]={1,2,3,4,5,6,7,0};
vector<int> x;
//求字符串长度,用strlen
int len=sizeof(a)/sizeof(int);
for(int i=0;i<len;i++){
x.push_back(a[i]);
}
printf("%d\n",InversePairs(x));
return 0;
}
#include<stdio.h>
#include<vector>
#include<iostream>
using namespace std;
#define Mod 1000000007
//需要修改vector数组的值,要用指针
int Find(vector<int>* data,int low,int high){
int ans=0;
if(low>=high) return ans;
int mid=(low+high)/2;
ans=(ans+Find(data,low,mid))%Mod;
ans=(ans+Find(data,mid+1,high))%Mod;
int i=low,j=mid+1;
vector<int> temp;
while(i<=mid&&j<=high){
if((*data)[i]>(*data)[j]){
ans=(ans+(mid-i+1))%Mod;
temp.push_back((*data)[j]);
j++;
}
else{
temp.push_back((*data)[i]);
i++;
}
}
while(i<=mid){
temp.push_back((*data)[i]);
i++;
}
while(j<=high){
temp.push_back((*data)[j]);
j++;
}
i=low;
for(int l=0;l<temp.size();l++){
(*data)[i++]=temp[l];
}
return ans%Mod;
}
int InversePairs(vector<int> data) {
int len=data.size();
return Find(&data,0,len-1);
}
int main()
{
int a[]={1,2,3,4,5,6,7,0};
vector<int> x;
//求字符串长度,用strlen
int len=sizeof(a)/sizeof(int);
for(int i=0;i<len;i++){
x.push_back(a[i]);
}
printf("%d\n",InversePairs(x));
return 0;
}
总结
两种写法,大致一致,一个使用全局变量,一个使用return。
发现一个问题:递归的时候必须这样写(low,mid)和(mid+1,high)
比如[1,2]--->mid=1--->(1,1)和(2,2)