【剑指Offer_8】数组中的逆序对

题目描述:

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

图一
图一

首先第一步是“分”,每次将数组分成平均的两部分,直到每一小部分只有一个元素。

第二步是“治”,按照归并排序的比较规则进行元素间的比较,得到有序序列。

图一中,有数组【3, 6, 4, 7, 9, 0, 2】,用土色笔写了元素间的比较。

 

2.

图二

如图二所示,将前面元素大于后面元素的都挑出来(绿色笔圈起来的),它们与逆序对有直接关联。

 

3.

图三

如图三所示,假设左右两部分为【a_{0},a_{1}...a_{m}】和【b_{0},b_{1}...b_{n}】,

对于每一个“a_{i}>b_{j}”,都有a_{i+1}>b_{j}...a_{m}>b_{j},,它们都是逆序对,所以计数个数为m-i+1,(绿色方框中的元素都是大于绿色圈右边元素的)

以最后一步为例:左边【3, 4, 6, 7】,右边【0, 2, 9】

  • 3先和0比较,3 > 0,而且左边是有序序列,因为3>0所以3之后的元素(4, 6, 7)> 0所以计数为4个。将较小值0放到结果序列的第一个位置。
  • 3再和2比较,3 > 2,同理(4, 6, 7)> 2,计数为4,将较小值2放到结果序列的后面。
  • 3和9比较,3 < 9,不计数,将较小值3放到结果序列的后面。
  • ...
  • 7和9比较,7 < 9,不计数,将较小值7放到结果序列的后面。
  • 最后只剩下9,将9放在结果序列的后面,得到有序的结果序列【0, 2, 3, 4, 6, 7, 9】,同时完成逆序对的计数。

4.

图四

图四所示,将所有绿色框内的元素个数加起来就是答案。

 

 

C++版:

class Solution {
private:
    vector<int> a;
    int count;
public:
    void mergeArray(int first,int mid,int last,int temp[])
    {
        int i=first,j=mid+1;//两部分数组开始下标
        int m=mid,n=last;   //两部分数组结束坐标
        int k=0;
        while(i<=m&&j<=n)
        {
            if(a[i]<=a[j])
                temp[k++] = a[i++];
            else
            {
                count += (m - i + 1);
                count %= 1000000007;
                temp[k++] = a[j++];
            }
                
        }
        while(i <= m)
            temp[k++] = a[i++];
        while(j<=n)
            temp[k++] = a[j++];
        for(int i=0; i<k; i++)
            a[first+i]=temp[i];
    }
    void mergeSort(int first,int last,int temp[])    
    {
        if(first<last)
        {
            int mid = (first+last)/2;
            mergeSort(first,mid,temp);
            mergeSort(mid+1,last,temp);
            mergeArray(first,mid,last,temp);
        }
    }
    int InversePairs(vector<int> data) {
        a = data;
        int n = data.size();
        int temp[n+1];
        mergeSort(0,n-1,temp);
        return count%1000000007;
    }
};

Python版:

用Python写的同样的算法,但是Python会超时。

下面这段代码是超时的,可以忽略!

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.count = 0
    def InversePairs(self, data):
        # write code here
        def mergeArray(first, mid, last):
            i = first
            en1 = mid
            j = mid + 1
            en2 = last
            temp = []
            while i<=en1 and j<=en2:
                if data[i] <= data[j]:
                    temp.append(data[i])
                    i += 1
                else:
                    self.count += (en1 - i + 1)
                    temp.append(data[j])
                    j += 1
            while i <= en1:
                temp.append(data[i])
                i += 1
            while j <= en2:
                temp.append(data[j])
                j += 1
            data[first:first+len(temp)]=temp
              
        def mergeSort(first, last):
            if first < last:
                mid = (first + last) // 2
                mergeSort(first, mid)
                mergeSort(mid+1, last)
                mergeArray(first, mid, last)
                  
        mergeSort(0, len(data)-1)
        return self.count % 1000000007

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值