剑指offer:数组中的逆序对

题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数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);
    }
};

不知道为啥,两种的运行时间当数据很多时,超过了要求,不过算法是对的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值