剑指Offer之逆序对问题

版权声明:所有的博客仅仅作为个人笔记使用!!!!!!! https://blog.csdn.net/qq_35976351/article/details/83007607

问题描述

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

求解思路

归并排序的方法求解,这样获得的复杂度是 O ( N log N ) O(N\log N) 。思路如下:假设左右两侧区间是排好序并且已经统计完逆序对个数的序列,那么对这两个区间进行归并。假设左边的区间此时的下标移动到i,右边区间下标移动到j,左侧区间从l开始,右侧区间从m开始,整个区间到r结束,都是左闭右开的;那么,此时对于R[j]来说,逆序对的个数是m-l-i个,只有L[i]后边的比它大。这样递归地求解,并把左右两侧的逆序对和归并的逆序对加起来,就是总的逆序对的个数。

注意一个坑:要用长整型long表示,否则会超出int的范围无法通过!!!!题目对p取模暗示了这一点。。。。。MMP,wa了好几次发现的。。。。。。

AC代码

#include <bits/stdc++.h>
using namespace std;

class Solution {
  public:
    int InversePairs(vector<int> data) {
        if(data.empty()) {
            return 0;
        }
        return MergeSort(data, 0, data.size()) % 1000000007;
    }

    long Merge(vector<int>& vec, int l, int m, int r) {
        long num = 0;
        vector<int>L;
        L.assign(vec.begin() + l, vec.begin() + m);
        vector<int>R;
        R.assign(vec.begin() + m, vec.begin() + r);
        int i = 0, j = 0, t = l;
        while(i < m - l && j < r - m) {
            if(R[j] < L[i]) {
                num += m - l - i;
                vec[t] = R[j];
                ++j;
            } else {
                vec[t] = L[i];
                ++i;
            }
            ++t;
        }
        while(i < m - l) {
            vec[t] = L[i];
            ++t;
            ++i;
        }
        while(j < r - m) {
            vec[t] = R[j];
            ++t;
            ++j;
        }
        return num;
    }

    long MergeSort(vector<int>&vec, int l, int r) {
        if(l >= r - 1) { // 只有一个元素
            return 0;
        }
        int m = l + (r - l) / 2;
        long n1 = MergeSort(vec, l, m);
        long n2 = MergeSort(vec, m, r);
        long n3 = Merge(vec, l, m, r);
        return n1 + n2 + n3;
    }
};

int main() {
    Solution so;
    vector<int>vec{10, 1, 2, 3, 4, 5, 6, 7, 0};
    cout << so.InversePairs(vec);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35976351/article/details/83007607