0
点赞
收藏
分享

微信扫一扫

BM20 数组中的逆序对

陈情雅雅 2022-05-05 阅读 94

描述

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


数据范围:  对于 50%50\%50% 的数据, size≤104size\leq 10^4size≤104
对于 100%100\%100% 的数据, size≤105size\leq 10^5size≤105

数组中所有数字的值满足 0≤val≤10000000 \le val \le 10000000≤val≤1000000
 

要求:空间复杂度 O(n)O(n)O(n),时间复杂度 O(nlogn)O(nlogn)O(nlogn)

输入描述:

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

示例1

输入:

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

返回值:

7

示例2

输入:

[1,2,3]

返回值:

0

题解:

对于该题如果使用暴力算法,使用for循环判断是否有比当前值大的值进行统计。我们首先看下暴力算法

class Solution {
private:
    const int kmod = 1000000007;
public:
    int InversePairs(vector<int> data) {
        int ret = 0;
        int n = data.size();
        for (int i = 0; i < n; ++i) {
            for (int j = i + 1; j < n; ++j) {
                if (data[i] > data[j]) {
                    ret += 1;
                    ret %= kmod;
                }
            }
        }

        return ret;
    }
};

这种算法会使时间复杂度上升为n^2,那有没有一种比较高效的算法呢。对于逆序对我们采用归并思想来解题。

归并排序过程主要有以下两个操作:

  • 递归划分整个区间为基本相等的左右两个区间
  • 合并两个有序区间

递归划分的终止标准是只有一个元素时开始向上合并,然后在程序中进行左右划分操作

class Solution {
public:
    int mod = 1000000007;
    int mergeSort(int left, int right, vector<int>& data, vector<int>& temp)
    {
        if(left >= right)    //递归终止条件
            return 0;
        int mid = left + (right - left)/2;    //求数组下标中值
        int res = mergeSort(left,mid,data,temp) +mergeSort(mid+1,right,data,temp);//统计递归下去得到的逆序对数和
        res %= mod;    //防止内存溢出
        int i=left,j=mid+1;
        for(int k=left; k<=right; k++){
            temp[k] = data[k];    //将待排序数组复制到新空间
        }
        for(int k=left; k<=right; k++){    //对数组进行排序操作,并统计逆序对数
            if(i == mid+1)                 //当左侧数组排完时,i=mid+1
                data[k] = temp[j++];       //将右侧数组加到排序数组中
            else if(temp[i]<=temp[j] || j==right+1)   //左侧数组小于右侧数组 或 右侧数组排完
                data[k] = temp[i++];       //将左侧数组加到排序数组中
            else{
                data[k] = temp[j++];       //左侧数组大于右侧时,将右侧加到排序数组中
                res += mid-i+1;    //统计逆序对数
            }
        }
        return res % mod;
    }
    int InversePairs(vector<int> data) {
        int n = data.size();
        vector<int> res(n);
        return mergeSort(0,n-1,data,res);
    }
};

在这里有一个不好理解的点是统计逆序对数时用res += mid - i +1

当左侧比较元素大于右侧比较元素时,左侧i位置到mid位置的所有元素均大于右侧比较元素(因为是归并排序上来的,左右两侧的数组都是有序的),此时增加的逆序对数为mid - i + 1

然后再逐级向上传递统计的逆序对数再进行进行统计,就得到了总的逆序对数。

举报

相关推荐

0 条评论