zoukankan      html  css  js  c++  java
  • 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。













    种一棵树最好的时间是十年前,其次是现在。
  • 相关阅读:
    linux常用命令---文件操作
    Django 框架中定时触发脚本
    jquery 中选择当前标签下众多相同子标签中的第n个
    Django + DRF + Elasticsearch 实现搜索功能
    django 使用celery 实现异步任务
    python 通过 pymysql模块 操作 mysql 数据库
    django 自定义中间件 middleware
    django 使用其自带的验证系统 进行用户名有效性验证 登录状态验证 登入操作 登出操作
    python脚本 读取excel格式文件 并进行处理的方法
    python 将json格式的数据写入csv格式的文件中
  • 原文地址:https://www.cnblogs.com/islch/p/13404431.html
Copyright © 2011-2022 走看看