【编程刷题笔记】数组中的逆序对

数组中的逆序对

描述

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

数据范围: 对于 50 的数据, s i z e ≤ 1 0 4 size≤10^4 size104
对于 100%的数据, s i z e ≤ 1 0 5 size≤10^5 size105
数组中所有数字的值满足 0≤val≤10000000

要求:空间复杂度 O(n),时间复杂度 O(nlogn)
输入描述:
题目保证输入的数组中没有的相同的数字

原题链接

分析

暴力法:
首先确定一个基准元素arr[i],依次判断索引大于i的元素,其空间复杂度为 O ( 1 ) O(1) O(1),时间复杂度为 O ( N 2 ) O(N^2) O(N2)
显然与题目中的要求在时间复杂度上不匹配。

题解

这个题目的一个比较理想的做法是采用分治策略,采用归并排序类似的思路进行合并,其具体步骤如下。
这个题目和分治的重点一样,重点不在,而在于

(1)分:将数组分为左右两个长度相当的部分,直至其长度为1。
(2)合:按照归并排序的思想进行归并排序,不过在合的时候需要在比较的时候,计数左边部分比右边部分大的组合。

例如:
如果两个区间为[4, 3] 和[1, 2]
那么逆序数为(4,1),(4,2),(3,1),(3,2),同样的如果区间变为有序,比如[3,4] 和 [1,2]的结果是一样的,也就是说区间有序和无序结果是一样的。
但是如果区间有序会有什么好处吗?当然,如果区间有序,比如[3,4] 和 [1,2]
如果3 > 1, 显然3后面的所有数都是大于1, 这里为 4 > 1,所以我们可以在合并的时候利用这个规则。

通过上述分析可以看出其时间复杂度为 O ( N l o g N ) O(N log N) O(NlogN),空间复杂度为 O ( n ) O(n) O(n)

代码

class Solution:
    def merge(self, left, right):
        length_left = len(left)
        length_right = len(right)
        out = []
 
        i, j = 0, 0
        while i < length_left and j < length_right:
            if left[i] > right[j]:
                self.res += length_left - i
                out.append(right[j])
                j += 1
            else:
                out.append(left[i])
                i += 1
        if i == length_left:
            while j < length_right:
                out.append(right[j])
                j += 1
        if j == length_right:
            while i < length_left:
                out.append(left[i])
                i += 1
 
        return out
 
    def divide_merge(self, data):
        length = len(data)
        # if length == 1:
        #     return data,[]
        if length == 3:
            if data[1] > data[2]:
                self.res += 1
                return [data[0]],[data[2],data[1]]
            else:
                return [data[0]], data[1:]
        if length == 2:
            return [data[0]], [data[1]]
        mid = length // 2
        left_0, right_0 = self.divide_merge(data[:mid])
        left = self.merge(left_0, right_0)
 
        left_1, right_1 = self.divide_merge(data[mid:])
        right = self.merge(left_1, right_1)
        out = self.merge(left, right)
 
        return out,[]
 
    def InversePairs(self, data):
        # write code here
        self.res = 0
        self.divide_merge(data)
        return self.res % 1000000007
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值