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。

猜你喜欢

转载自www.cnblogs.com/islch/p/13404431.html