牛客剑指Offer面试题51:数组中的逆序对(归并排序,待复习递归思想)

题目描述

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数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.右数组起始索引为start + Index + 1
2.牛客已知题干与书上不同,要求%100000007, 需使用long long 类型数?
C++Primer中写道:如果数值超过了int的表示范围,则用long long.(实际应用中,short显得太小,而long和int一般有一样的尺寸)
3.函数传入参数时copy和data互换?
4.归并算法实现使用递归的理解可以参考Python数据结构笔记及视频

代码

class Solution {
public:
    int InversePairs(vector<int> data) {
        //判断有效性
        if(data.empty())
            return 0;
        int length = data.size();
        //创建辅助数组
        vector<int> copy;
        //拷贝data内元素至copy中
        for(int i = 0; i < length; ++i)
            copy.push_back(data[i]);
        
        long long totalNum = InversePairsCore(data, copy, 0, length - 1);
        return totalNum%1000000007;
    }
    
    
    long long InversePairsCore(vector<int>& data, vector<int>& copy, int start, int end)
    {
        //划分至只有一个元素
        if(start == end)
        {
            copy[start] = data[start];
            return 0;
        }
        //用游标将数组划分为2
        int Index = (end - start) / 2;
        
        long long left = InversePairsCore(copy, data, start, start + Index);
        long long right = InversePairsCore(copy, data,start + Index + 1, end);
        //辅助数组游标指向末尾
        int indexOfCopy = end;
        //声明两个游标分别指向每个左右数组的末尾元素
        int i = start + Index;
        int j = end;
        //声明变量记录逆序对数量
        long long count = 0;
        //当左右数组内元素未遍历完
        while(i >= start && j >= start + Index + 1)
        {
            //如果左数组末尾元素大于右数组末尾元素
            if(data[i] > data[j])
            {
                copy[indexOfCopy--] = data[i--];
                //此时右数组所有元素都与左数组游标所指元素构成逆序对,数量为右数组元素数量
                count += (j - start - Index);
            }
            //左数组末尾元素小于右数组末尾元素
            else
            {
                //将右数组末尾元素拷贝至辅助数组,并前移两个游标
                copy[indexOfCopy--] = data[j--];
            }
        }
        //如右(左)数组已复制完毕,但左(右)数组内还有元素,则复制剩余元素到辅助数组中
        //如果右子数组拷贝完毕,则继续拷贝剩余左子数组
        for(; i >= start ; --i)
            copy[indexOfCopy--] = data[i];
        //如果左子数组拷贝完毕,则继续拷贝剩余右子数组
        for(; j >= start + Index + 1; --j)
            copy[indexOfCopy--] = data[j];
        return count + left + right;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值