• leetcode 剑指 Offer 51. 数组中的逆序对


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

    示例 1:
    输入: [7,5,6,4]
    输出: 5
     

    直接两次遍历是不行的,时间肯定会超。这里用到了归并排序中归并这一步的思想,来求逆序对。

    浏览答案中会发现两个代码极为相似的,但是第二个代码多了一句
    困扰许久,wdtmd我是真的蠢

    官方的python版本

    from typing import List
    
    class Solution:
        def mergeSort(self, nums, tmp, l, r):
            if l >= r:
                return 0
    
            mid = (l + r) // 2
            inv_count = self.mergeSort(nums, tmp, l, mid) + self.mergeSort(nums, tmp, mid + 1, r)
            i, j, pos = l, mid + 1, l
            while i <= mid and j <= r:
                if nums[i] <= nums[j]:
                    tmp[pos] = nums[i]
                    i += 1
                    inv_count += (j - (mid + 1))
                else:
                    tmp[pos] = nums[j]
                    j += 1
                pos += 1
            for k in range(i, mid + 1):
                tmp[pos] = nums[k]
                inv_count += (j - (mid + 1))
                pos += 1
            for k in range(j, r + 1):
                tmp[pos] = nums[k]
                pos += 1
            nums[l:r+1] = tmp[l:r+1]
            return inv_count
    
        def reversePairs(self, nums: List[int]) -> int:
            n = len(nums)
            tmp = [0] * n
            return self.mergeSort(nums, tmp, 0, n - 1)
    
    a = Solution().reversePairs([7,5,4,6])
    print(a)
    

    一个作者的python版本

    from typing import List
    
    class Solution:
        def reversePairs(self, nums: List[int]) -> int:
            self.cnt = 0
    
            def merge(nums, start, mid, end):
                i, j, temp = start, mid + 1, []
                while i <= mid and j <= end:
                    if nums[i] <= nums[j]:
                        temp.append(nums[i])
                        i += 1
                    else:
                        self.cnt += mid - i + 1
                        temp.append(nums[j])
                        j += 1
                while i <= mid:
                    temp.append(nums[i])
                    i += 1
                while j <= end:
                    temp.append(nums[j])
                    j += 1
    
                for i in range(len(temp)):
                    nums[start + i] = temp[i]
    
            def mergeSort(nums, start, end):
                if start >= end: return
                mid = (start + end) >> 1
                mergeSort(nums, start, mid)
                mergeSort(nums, mid + 1, end)
                merge(nums, start, mid, end)
    
            mergeSort(nums, 0, len(nums) - 1)
            return self.cnt
    
    
    a = Solution().reversePairs([7,5,6,4])
    print(a)
    

    困扰的地方就是对count这部分的加法,官方出现了两次,另一作者是一次,解析如下:
    对于归并的两个数组[i,mid], [mid+1,j]
    官方解法是当第一个子数组中的数字A进入到temp数组中的时候,那么这个时候第二个数组中下标指针前面的数就都比这个A要小,因为他们已经进入了temp,所以加。
    然后当while i <= mid and j <= r:这个判定不成立的时候,如果第一个数组还有没进入temp的,那么同理,右边数组里面剩下的肯定都比这个小。

    另外作者解法只有在while i <= mid and j <= end:且if nums[i] <= nums[j]都不成立时候才加count,他的意思是当左边数组当前数字A比右边数组当前数字B大的时候,那么这时候就说明,第一个数组中A右边的数字都比B大(因为两个子数组都是有序的),所以加mid - i + 1,如果while i <= mid and j <= end这个判定已经不成立了,那么如果左边数组还有数字,那么说明右边的数组都加到temp了,每次右边数字加进去的时候都会计算,不会遗漏;如果右边数组还有数字,那么这些数字都比左边的大了,也不用加count。













    种一棵树最好的时间是十年前,其次是现在。
  • 相关阅读:
    经典小程序源码及其下载地址
    基于cropper.js的图片上传和裁剪
    【组件】微信小程序input搜索框的实现
    如何打造个人技术影响力
    一位90后程序员的自述:如何从年薪3w到30w!
    状态模式(State)(开关灯,状态实例为类,不同状态,不同行为)
    责任链模式(Chain of Responsibility、Handler)(请求处理建立链)
    java中创建对象的五种方法
    PrintWrite
    观察者模式(Observer、Subject、ConcreteSubject、ConcreteObserver)(监护、订阅)
  • 原文地址:https://www.cnblogs.com/islch/p/13404431.html
Copyright © 2020-2023  润新知