剑指offer-51.数组中的逆序对

题目来源:https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof/

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

 

示例 1:

输入: [7,5,6,4]
输出: 5

思路:

利用归并排序,归并排序在倒数第二步(即最后的合并之前)会得到左右两个已经排序的子数组,从这里可以得到逆序对数量。

逆序对是归并排序的副产物

举例来说,假设一个数组为[3, 4, 1, 2, 7, 6],划分为两组后,经过归并排序,在最后合并前两个子数组分别为:[1, 3, 4]和[2, 6, 7],假设某时刻,指针i指向3,指针j指向2,那么对于2来说就有逆序对mid - i + 1 = 2 - 1 +  1 = 2对(其实就是len(left) - i),因为左边数组是有序的,如果i位置的数大于j位置的数,那么i之后数也肯定大于j位置的数。所以,统计每次归并时的逆序对数就行了。

class Solution(object):
    def reversePairs(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        self.cnt = 0
        def merge(nums, start, mid, end):          # 归并
            i = start
            j = mid + 1
            res = []
            while i <= mid and j <= end:
                if nums[i] <= nums[j]:
                    res.append(nums[i])
                    i += 1 
                else:                              # nums[i]>nums[j],则统计当前数组内的逆序对数
                    self.cnt += mid - i + 1        # mid + 1其实就是左子数组的长度
                    res.append(nums[j])
                    j += 1
            
            while i <= mid:
                res.append(nums[i])
                i += 1
            while j <= end:
                res.append(nums[j])
                j += 1

            for i in range(len(res)):
                nums[start + i] = res[i]       # 更新nums
            
        def mergesort(nums, start, end):     
            if start >= end:
                return 
            mid = (start + end) // 2 
            mergesort(nums, start, mid)       # 递归,左子数组继续归并
            mergesort(nums, mid + 1, end)     # 递归,右子数组继续归并
            merge(nums, start, mid, end)      # 归并
        
        mergesort(nums, 0, len(nums)-1)
        return self.cnt

参考:

https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof/solution/jian-dan-yi-dong-gui-bing-pai-xu-python-by-azl3979/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值