数组中的逆序对(时间空间效率的平衡)

题目描述

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数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)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值