数组中的逆序对(数组)

剑指OFFER 专栏收录该内容
34 篇文章 2 订阅

描述

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


对于50\%50%的数据,size\leq 10^4size≤104
对于75\%75%的数据,size\leq 10^5size≤105
对于100\%100%的数据,size\leq 2*10^5size≤2∗105

输入描述:

题目保证输入的数组中没有的相同的数字

示例1

输入:

[1,2,3,4,5,6,7,0]

复制返回值:

7

思路:

这题一开始想最简单的两层遍历,找出总个数除%100000007得到结果,但是这样只能过2/3组用例,题目还有一个限制条件,对于数据是有范围限制的,对于10的5次方数据肯定是超时了。转换一下思路,想到后面的数小于前面的数构成逆序,在归并排序中,后一组的数小于前一组的数,两者并到一起构成一个有序数列。并且归并排序的复杂度是O(nlogn),在算法复杂度上可以进一步缩减。归并就是将大问题不断分解为小问题,直到不能再分,解决了小的问题后在合并到一起解决整个问题。对于归并排序来讲,分为两组,分别比较两组数的大小,先用第一组的数分别和后面的第一个数比较,小的话就记录,否则就记录后面的数,注意,当找到一个比后面第一个大的数的时候,那么当前数的后面的数都是大于后面第一个数的,这样就形成了逆序对,用后面第一个数的下标减去当前数的下标就得到了逆序对个数,总体遍历完就可以得到总的个数。

这里再放一下归并排序过程,图片来自归并排序图解,顺便复习下:

 

class Solution {
public:
    int temp[200010];
    int InversePairs(vector<int> a) {
        //对原数组进行归并排序
        int n = a.size();
        if(n <= 1) return 0;
        return mergeSort(a, 0, n - 1);
    }
    
    int mergeSort(vector<int> &a, int l, int r)
    {
        if(l >= r) return 0;
        
        int mid = (l + r) / 2;
        //左边排序值传给x
        long long x = mergeSort(a, l, mid);
        //右边排序值传给y
        long long y = mergeSort(a, mid + 1, r);
        
        long long t = 0;
        int i = l;//左指针
        int j = mid + 1;//右指针
        int k = 0;//临时指针
        
        //进行归并排序,用左边的值分别和右边的第一个值开始比较
        while(i <= mid && j <= r)
        {
            if(a[i] <= a[j])
            {
                //从第一个开始,每一个和右边第一个的比,小就记录。
                temp[k++] = a[i++];
            }
            else
            {
                //当前值大的时候,就吧右边的第一个值插入到队列,此时相当于找到一个逆序对,那么这个数的后面都是大于a[j]的,
                //用j-i表示一共的逆序对数。t就表示一共找到的逆序对数。
                t += mid - i + 1;
                temp[k++] = a[j++];
            }
        }
        //将左边剩余元素放入temp[]
        while(i <= mid) 
            temp[k++] = a[i++];
        //将左边剩余元素放入temp[]
        while(j <= r) 
            temp[k++] = a[j++];
        
        //将所有元素放入数组
        for(int i = l, k = 0; i <= r; i++)
        {
            a[i] = temp[k++];
        }
        return (x + y + t) % 1000000007;
    }
};

 

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: Age of Ai 设计师:meimeiellie 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值