【剑指offer】数组中的逆序对

题目描述

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数 P P P。并将 P P P 1000000007 1000000007 1000000007取模的结果输出。 即输出 P P%1000000007 P
输入描述:
题目保证输入的数组中没有的相同的数字

数据范围:

对于%50的数据, s i z e &lt; = 1 0 4 size&lt;=10^4 size<=104

对于%75的数据, s i z e &lt; = 1 0 5 size&lt;=10^5 size<=105

对于%100的数据, s i z e &lt; = 2 ∗ 1 0 5 size&lt;=2*10^5 size<=2105

示例1
输入
1 , 2 , 3 , 4 , 5 , 6 , 7 , 0 1,2,3,4,5,6,7,0 1,2,3,4,5,6,7,0
输出
7 7 7

思路:

1)遍历整个数组,每遍历到一个数字,就逐个比较该数字和它后面的数字的大小,如果后面的数字比它小,则这两个数字就组成一个逆序对。假设数组中含有 n n n个数字,由于每个数字都要和 O ( n ) O(n) O(n)个数字进行比较,因此时间复杂度为 O ( n 2 ) O(n^2) O(n2)

2)考虑归并思路。先将数组分为若干个长度相等的子数组,然后在合并子数组的时候进行排序、并统计逆序对,时间复杂度为归并排序的 O ( n l o g n ) O(nlog{n}) O(nlogn)

class Solution {
public:
    int InversePairs(vector<int> data) {
       int length=data.size();
        if(length<=0)
            return 0;
       vector<int> copy;
       //复制元素到辅助数组
       for(int i=0;i<length;i++)
           copy.push_back(data[i]);
       long long count=InversePairsCore(data,copy,0,length-1);
       return count%1000000007;
    }
    long long InversePairsCore(vector<int> &data,vector<int> &copy,int start,int end)
    {
       if(start==end){
           copy[start]=data[start];
           return 0;
       }
       int length=(end-start)/2;
       //分为若干个子数组
       long long left=InversePairsCore(copy,data,start,start+length);
       long long right=InversePairsCore(copy,data,start+length+1,end);
         
       int i=start+length;
       int j=end;
       int indexcopy=end;
       long long count=0;
       while(i>=start&&j>=start+length+1){
       		//合并过程中判断逆序对,i为前半段最后一个数字的下标,j为后半段最后一个数字的下标
             if(data[i]>data[j]){
                 copy[indexcopy--]=data[i--];
                 //由于j表示的是后半段的最大数字,所以如果data[i]>data[j]则加上后半段到j的数字个数
                 count=count+j-start-length;         
             }
             else{
                 copy[indexcopy--]=data[j--];
             }         
       }
       for(;i>=start;i--)
           copy[indexcopy--]=data[i];
       for(;j>=start+length+1;j--)
           copy[indexcopy--]=data[j];      
       return left+right+count;
    }
};

关于交换 c o p y copy copy d a t a data data的解释

作者:牛客8918164号
链接:https://www.nowcoder.com/questionTerminal/96bd6684e04a44eb80e6a68efc0ec6c5
来源:牛客网

交换 c o p y copy copy d a t a data data是因为:
1.在每次的操作中,数值的比较都是采用当前传入函数中第一项,也就是 d a t a data data;比较的结果都存放到 c o p y copy copy中;也就意味着此时 c o p y copy copy中是经过此次调用的结果。
2.从最底层返回时,进入了( s t a r t = = e n d start == end start==end)的情形, d a t a data data c o p y copy copy 完全没有修改,此时 c o p y copy copy d a t a data data还是一样的。
3.进入倒数第二层时,程序进入上图26行以后部分, c o p y copy copy是部分排序后的新数组, d a t a data data是旧数组。注意这里都是传值的调用,数组都是直接修改的。
倒数第二层使用的 c o p y copy copy其实是倒数第三层中的data,这就确保了倒数第三层进入26行以后时,数据比较使用的 d a t a data data是最新排序的数组。
4. 倒数第三层将排序的结果存入 c o p y copy copy中。程序在倒数第四层进入26行后,使用的 d a t a data data数组为刚刚倒数第三层中的最新排序的 c o p y copy copy.
5. 也就是说,在每次程序进入26行时,此时的 d a t a data data是最新的排序结果, c o p y copy copy是次新的结果。 在最后一次进入26行以后时, c o p y copy copy为完整排序后的结果, d a t a data data是次新的结果。
然而这里第一个类内函数调用第二个函数时, d a t a data data c o p y copy copy的顺序没有改变,所以最后结果应该 c o p y copy copy是完整排序的结果. d a t a data data是差一步完成排序的结果。以输入 [ 7 , 5 , 6 , 4 ] [7,5,6,4] [7,5,6,4],
最后的结果 c o p y [ 4 , 5 , 6 , 7 ] , d a t a [ 5 , 7 , 4 , 6 ] . copy[4,5,6,7], data[5,7,4,6]. copy[4,5,6,7],data[5,7,4,6].

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值