剑指offer(15)--数组中的逆序对

考点:归并排序、逆序对

题目描述

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007

思路分析

这是一个归并排序的过程,主要考虑合并两个有序序列时,计算逆序对。

逆序对,前面数字大于后面数字,相当于研究右边有多少比左边当前数小。对于两个升序序列,设置两个下标在左右两个有序序列末尾。每次比较两个末尾值,如果前末尾大于后末尾,则前末尾大于后面所有数,即逆序对数为“后面有序当前长度”个。否则不构成逆序对。然后把较大数拷贝到数组末尾,拷贝的这个指针前移。最终要将两个有序序列合并到辅助数组并有序。

这样在递归前,先递归处理左右半段,则左右有序(将有序数组通过地址传参传回),且左右段逆序对可以得到。再计算左右合并过程时产生的逆序对个数。

7>5,1个逆序对,辅助数组[5,7];6>4,1个逆序对,辅助数组[4,6]。57(由辅助数组返回的data值),46,p1指针在7,p2在6,7大于6,2个逆序对,7入辅助数组,p1前移;5<6无逆序对,6入辅助数组,p2前移;5>4,1个逆序对,5入辅助数组。最后4入辅助数组。最终辅助数组[4,5,6,7],逆序对共5对

核心代码如下:

        int i=r;
        int p1=m;
        int p2=r;
        int count=0;
        while(p1>=l && p2>=m+1){
            count+=data[p1]>data[p2] ? (p2-m):0;
            help[i--]=data[p1]>data[p2] ? data[p1--]: data[p2--];
        }
        while(p1>=l){
            help[i--]=data[p1--];
        }
        while(p2>=m+1){
            help[i--]=data[p2--];
        }

实现代码

1.完全正确版。将data、help通过地址传参节省空间。递归调用时,help传给data,data传给help,实现交换,将Help赋值给data

class Solution {
public:
    int InversePairs(vector<int> data) {
        if(data.size()<2)
            return 0;
        vector<int>help (data.begin(), data.end());
        long count=0;
        count=(InversePairsCore(data,help,0,data.size()-1));
        return count%1000000007;
    }
    long InversePairsCore(vector<int> &data,vector<int> &help,int l,int r){
        if(l==r)
            return 0;
        int mid=l+((r-l)>>1);
        return InversePairsCore(help,data,l,mid)+InversePairsCore(help,data,mid+1,r)
            +merge(data,help,l,mid,r);
    }
    long merge(vector<int> &data,vector<int> &help, int l,int m,int r){
        
        int i=r;
        int p1=m;
        int p2=r;
        long count=0;
        while(p1>=l && p2>=m+1){
            count+=data[p1]>data[p2] ? (p2-m):0;
            help[i--]=data[p1]>data[p2] ? data[p1--]: data[p2--];
        }
        while(p1>=l){
            help[i--]=data[p1--];
        }
        while(p2>=m+1){
            help[i--]=data[p2--];
        }
       // for(i=0;i<help.size();i++){
        //    data.push_back(help[i]);
       // }
        
        //help.swap(data);
        
        //把help复制给data
        //data.assign(help.begin(), help.end());
        //help.clear(); 
        return count;
    }
};

2.只传data参数,help占空间。最后释放help数组给data;

运行超时,可通过50%测试

class Solution {
public:
    int InversePairs(vector<int> data) {
        if(data.size()<2)
            return 0;
        long long count=0;
        count=(InversePairsCore(data,0,data.size()-1));
        return count%1000000007;
    }
    long long InversePairsCore(vector<int> &data,int l,int r){
        if(l==r)
            return 0;
        int mid=l+((r-l)>>1);
        return InversePairsCore(data,l,mid)+InversePairsCore(data,mid+1,r)
            +merge(data,l,mid,r);
    }
    long long merge(vector<int> &data,int l,int m,int r){
        vector<int>help (data.begin(), data.end());
        int i=r;
        int p1=m;
        int p2=r;
        int count=0;
        while(p1>=l && p2>=m+1){
            count+=data[p1]>data[p2] ? (p2-m):0;
            help[i--]=data[p1]>data[p2] ? data[p1--]: data[p2--];
        }
        while(p1>=l){
            help[i--]=data[p1--];
        }
        while(p2>=m+1){
            help[i--]=data[p2--];
        }
       // for(i=0;i<help.size();i++){
        //    data.push_back(help[i]);
       // }
         
        help.swap(data);
        
        //把data赋值为help;
        //data.assign(help.begin(), help.end());
        //help.clear();
        return count;
    }
};

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值