牛客网-C++剑指offer-第三十五题(数组中的逆序对)

题目描述

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数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

解题思路:并归分治

(a) 把长度为4的数组分解成两个长度为2的子数组;

(b) 把长度为2的数组分解成两个成都为1的子数组;

(c) 把长度为1的子数组 合并、排序并统计逆序对

(d) 把长度为2的子数组合并、排序,并统计逆序对;

在上图(a)和(b)中,我们先把数组分解成两个长度为2的子数组,再把这两个子数组分别拆成两个长度为1的子数组。接下来一边合并相邻的子数组,一边统计逆序对的数目。在第一对长度为1的子数组{7}、{5}中7大于5,因此(7,5)组成一个逆序对。同样在第二对长度为1的子数组{6}、{4}中也有逆序对(6,4)。由于我们已经统计了这两对子数组内部的逆序对,因此需要把这两对子数组 排序 如上图(c)所示, 以免在以后的统计过程中再重复统计。

接下来我们统计两个长度为2的子数组子数组之间的逆序对。合并子数组并统计逆序对的过程如下图如下图所示。

我们先用两个指针分别指向两个子数组的末尾,并每次比较两个指针指向的数字。如果第一个子数组中的数字大于第二个数组中的数字,则构成逆序对,并且逆序对的数目等于第二个子数组中剩余数字的个数,如下图(a)和(c)所示。如果第一个数组的数字小于或等于第二个数组中的数字,则不构成逆序对,如图b所示。每一次比较的时候,我们都把较大的数字从后面往前复制到一个辅助数组中,确保 辅助数组(记为copy) 中的数字是递增排序的。在把较大的数字复制到辅助数组之后,把对应的指针向前移动一位,接下来进行下一轮比较。

参考答案:

#include <iostream>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
#include<algorithm>
#include <string>

using namespace std;

class Solution {
public:

    vector<int> my_temp;
    long long count;
    void Separate(vector<int>& data, int start, int end)
    {
        if (start>=end)
        {
            return;
        }

        int mid = start + (end-start)/2;

        Separate(data,start,mid);
        Separate(data,mid+1,end);

        rule(data,start,end,mid);
    }

    void rule(vector<int>& data, int start, int end, int mid)
    {

        int left = mid;
        int right = end;
        int k = end;

        if (left >= right)
            return;

        my_temp.clear();
        while (left >= start && right >= mid+1)
        {
            if (data[left] > data[right])
            {
                my_temp[k--] = data[left--];
                if(end >= mid + 1)
                    count += (right-mid);
            } else{
                my_temp[k--] = data[right--];
            }
        }

        while (left >= start)
        {
            my_temp[k--] = data[left--];
        }

        while (right >= mid+1)
        {
            my_temp[k--] = data[right--];
        }

        for (int i = start; i < end + 1; ++i) {
            data[i] = my_temp[i];
        }
    }

    int InversePairs(vector<int>& data) {
        if (data.empty())
            return 0;

        int start = 0;
        int end = data.size()-1;
        my_temp.resize(data.size());

        count=0;
        Separate(data,start,end);

        return count%1000000007;
    }
};

int main()
{
    Solution solution;

    int a[] = {364,637,341,406,747,995,234};

    vector<int> my_v(a,a+7);

    cout<<solution.InversePairs(my_v)<<endl;
    for (int i = 0; i < my_v.size(); ++i) {
        cout<<my_v[i]<<" ";
    }

    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值