在合并的过程中统计逆序对的数量:
合并阶段 本质上是 合并两个排序数组 的过程,而每当遇到 左子数组当前元素 > 右子数组当前元素 时,意味着 「左子数组当前元素 至 末尾元素」 与 「右子数组当前元素」 构成了若干 「逆序对」 。
重点:如何在归并排序中记录逆序对的数量的,沿用归并排序的模板
方法一:采用暴力解法
采用两层循环来写

class Solution:
    def reversePairs(self, nums: List[int]) -> int:
        res = 0
        for i in range(len(nums)-1):
            for j in range(i +1,len(nums)):
                if nums[i] >nums[j]:
                    res +=1
运行结果:超时

方法二:采用归并排序的思路来解题
复杂度分析:
时间复杂度 O(Nlog⁡N): 其中 N为数组长度;归并排序使用 O(Nlog⁡N) 时间;
空间复杂度 O(N): 辅助数组 tmptmptmp 占用 O(N)大小的额外空间

class Solution:
    def reversePairs(self, nums: List[int]) -> int: 
        def merge_sort(nums, left, right):
            #子数组长度为1,终止划分,需要开始解决
            if left >= right:
                return 0

            #计算数组的中间位置
            mid = left + (right - left) // 2
            
            #调用merge_sort函数,递归划分左子数组
            cnt_l = merge_sort(nums, left, mid)
            #调用merge_sort函数,递归划分右子数组
            cnt_r = merge_sort(nums, mid + 1, right)
            #调用merge函数,将nums数组中三块区域合并
            cnt_c = merge(nums, left, mid, right)
            return cnt_l + cnt_r + cnt_c

        def merge(nums, left, mid, right):
            #初始化变量以及数组,用于合并阶段暂存元素以及统计逆序对
            tmp, cnt = [], 0
            #定义双指针,分别指向左右子数组的首元素
            l1, l2 = left, mid + 1
            
            #循环合并
            #循环条件:左区间的首元素<=中间元素,并且右区间的首元素<=末尾元素
            while l1 <= mid and l2 <= right:
                #左区间的首元素<右区间的首元素,不需要动逆序对的数量
                if nums[l1] <= nums[l2]:
                    tmp.append(nums[l1])
                    l1 += 1
                #左边的数和右边的数共同组成了逆序对
                else:
                    tmp.append(nums[l2])
                    l2 += 1
                    cnt += (mid - l1 + 1) #统计逆序对数

            # 如果左区间中还有元素,那么把它都添加到 result 中
            if l1 <= mid:
                tmp.extend(nums[l1 : mid + 1])
            # 如果右区间中还有元素,那么把它都添加到 result 中
            else:
                tmp.extend(nums[l2 : right + 1])
            
            #把新数组中的数覆盖nums数组
            nums[left : right + 1] = tmp[:]
            return cnt

        return merge_sort(nums, 0, len(nums) - 1)

另一种简洁明了的版本:
https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof/solution/jian-zhi-offer-51-shu-zu-zhong-de-ni-xu-pvn2h/

class Solution:
    def reversePairs(self, nums: List[int]) -> int:
        def merge_sort(l, r):
            # 终止条件
            if l >= r: return 0
            # 递归划分
            m = (l + r) // 2
            res = merge_sort(l, m) + merge_sort(m + 1, r)
            # 合并阶段
            i, j = l, m + 1
            #做一个拷贝操作
            tmp[l:r + 1] = nums[l:r + 1]
            for k in range(l, r + 1):
                #左子数组已经合并完成,添加右子数组当前元素
                #逆序对数不变
                if i == m + 1:
                    nums[k] = tmp[j]
                    j += 1
                #右子数组已合并完成以及左区间的首元素<右区间的首元素,添加左子数组当前元素 
                #逆序对数不变
                elif j == r + 1 or tmp[i] <= tmp[j]:
                    nums[k] = tmp[i]
                    i += 1
                #左边的和右边的共同组成逆序对数,添加右子数组当前元素
                else:
                    nums[k] = tmp[j]
                    j += 1
                    res += m - i + 1 # 统计逆序对
            return res
        #初始化:辅助数组,用于合并阶段暂存元素
        tmp = [0] * len(nums)
        #返回值:执行归并排序merge_sort,并返回逆序对总数
        return merge_sort(0, len(nums) - 1)
ToTOP