LeetCode 刷题之旅(2020.04.24)——面试题51. 数组中的逆序对(难)

LeetCode 刷题之旅(2020.04.24)——面试题51. 数组中的逆序对(难)

题目:

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

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

限制:

0 <= 数组长度 <= 50000

解题模板:

class Solution:
    def reversePairs(self, nums: List[int]) -> int:

解题思路:

  • 归并排序
  • 分治思想
  • 二叉树后序遍历

暴力解题的做法不提倡,时间复杂度O(N^2)。这里用到分治的思想解题,有关排序问题应用分治思想的方法,归并排序是很好的例子。将整个问题简化,递归地解决简单问题,从而实现复杂问题的攻克。
如官方所给的例子:
LeetCode 刷题之旅(2020.04.24)——面试题51. 数组中的逆序对(难)_第1张图片
对于本题来说,数列的逆序数计算也可以一步步地分而治之

解法:

首先给出归并排序的代码:

def mergesort(nums, tmp, left, right):
    if left >= right:
        return
    mid = (right + left) // 2
    mergesort(nums, tmp, left, mid)
    mergesort(nums, tmp, mid+1, right)
    # 这里采用后序遍历(左→右→根)的方法
    i = left
    j = mid + 1
    k = left
    while i <= mid and j <= right:
        if nums[i] <= nums[j]:
            tmp[k] = nums[i]
            k += 1
            i += 1
        else:
            tmp[k] = nums[j]
            k += 1
            j += 1
    while i <= mid:
        tmp[k] = nums[i]
        k += 1
        i += 1
    while j <= right:
        tmp[k] = nums[j]
        k += 1
        j += 1
    for i in range(left, right+1):
        nums[i] = tmp[i]

tmp = [0] * len(nums)
mergesort(nums, tmp, 0, len(nums)-1)

时间复杂度O(N*logN),归并排序虽然不是排序算法中效率最高的,不过其分治的思想很重要!

class Solution:
    def reversePairs(self, nums: List[int]) -> List[int]:
        tmp = [0] * len(nums)

        def mergesort(nums, tmp, left, right):
            if left >= right:
                return 0
            mid = (right + left) // 2
            sum_ = mergesort(nums, tmp, left, mid)
            sum_ += mergesort(nums, tmp, mid+1, right)
            # 这里增加了计数器
            i = left
            j = mid + 1
            k = left
            while i <= mid and j <= right:
                if nums[i] <= nums[j]:
                    tmp[k] = nums[i]
                    k += 1
                    i += 1
                else:
                    tmp[k] = nums[j]
                    sum_ += mid - i + 1 # 统计失序数对的数量
                    k += 1
                    j += 1
            while i <= mid:
                tmp[k] = nums[i]
                k += 1
                i += 1
            while j <= right:
                tmp[k] = nums[j]
                k += 1
                j += 1
            for i in range(left, right+1):
                nums[i] = tmp[i]
            return sum_

        sum_ = mergesort(nums, tmp, 0, len(nums)-1)
        return sum_

时间复杂度O(N*logN)

你可能感兴趣的:(LeetCode每日一题,LeetCode难题)