LeetCode题解493.reverse-pairs

题目地址(493. 翻转对)

https://leetcode-cn.com/problems/reverse-pairs/description/

题目描述

给定一个数组 nums ,如果 i < j 且 nums[i] > 2*nums[j] 我们就将 (i, j) 称作一个重要翻转对。

你需要返回给定数组中的重要翻转对的数量。

示例 1:

输入: [1,3,2,3,1]
输出: 2
示例 2:

输入: [2,4,3,5,1]
输出: 3
注意:

给定数组的长度不会超过50000。
输入数组中的所有数字都在32位整数的表示范围内。

暴力法

思路

读完这道题你应该就能联想到逆序数才行。求解逆序数最简单的做法是使用双层循环暴力求解。我们仿照求解决逆序数的解法来解这道题(其实唯一的区别就是系数从 1 变成了 2)。

代码

代码支持:Python3

Python3 Code:

class Solution(object):
    def reversePairs(self, nums):
        n = len(nums)
        cnt = 0
        for i in range(n):
            for j in range(i + 1, n):
                if nums[i] > 2 * nums[j]:
                    cnt += 1
        return cnt

分治法

思路

如果你能够想到逆序数,那么你很可能直到使用类似归并排序的方法可以求解逆序数。实际上逆序数只是归并排序的副产物而已。

我们在正常的归并排序的代码中去计算逆序数即可。由于每次分治的过程,左右两段数组分别是有序的,因此我们可以减少一些运算。 从时间复杂度的角度上讲,我们从$O(N^2)$优化到了 $O(NlogN)$。

具体来说,对两段有序的数组,有序数组内部是不需要计算逆序数的。 我们计算逆序数的逻辑只是计算两个数组之间的逆序数,我们假设两个数组是 A 和 B,并且 A 数组最大的元素不大于 B 数组最小的元素。而要做到这样,我们只需要常规的归并排序即可。

接下来问题转化为求解两个有序数组之间的逆序数,并且两个有序数组之间满足关系A数组最大的元素不大于B数组最小的元素

关于计算逆序数的核心代码(Python3):

l = r = 0
while l < len(left) and r < len(right):
    if left[l] <= 2 * right[r]:
        l += 1
    else:
        self.cnt += len(left) - l
        r += 1

代码

代码支持:Python3

Python3 Code:

class Solution(object):
    def reversePairs(self, nums):
        self.cnt = 0

        def mergeSort(lst):
            L = len(lst)
            if L <= 1:
                return lst
            return mergeTwo(mergeSort(lst[:L//2]), mergeSort(lst[L//2:]))

        def mergeTwo(left, right):
            l = r = 0
            while l < len(left) and r < len(right):
                if left[l] <= 2 * right[r]:
                    l += 1
                else:
                    self.cnt += len(left) - l
                    r += 1
            return sorted(left+right)

        mergeSort(nums)
        return self.cnt

对于具体的排序过程我们偷懒直接使用了语言内置的方法 sorted,这在很多时候是有用的,即使你是参加面试,这种方式通常也是允许的。省略非核心的考点,可以使得问题更加聚焦,这是一种解决问题的思路,在工作中也很有用。

关键点解析

  • 归并排序
  • 逆序数
  • 分治
  • 识别考点,其他非重点可以使用语言内置方法

代码

扩展

这道题还有很多别的解法,感性的可以参考下这个题解 General principles behind problems similar to "Reverse Pairs"

LeetCode题解计算机为什么是基于二进制的?

可以是三进制么?二进制有什么好处?题解:为什么叫电子计算机?算盘应该没有二进制

LeetCode题解深度优先遍历和回溯的关系?

深度优先遍历的范围更大还是回溯的范围更大?为什么?题解:我的理解是:dfs是回溯思想的一种体现- 回溯:是在整个搜索空间中搜索出可行解,在搜索过程中不断剪枝回退,这是回溯的思想,这个搜索空间并没有限制于特定的数据结构。- dfs:dfs是指特定的数据结构中如图,树(特殊的图)中搜索答案,范围限制在了特定的数据结构。个人拙见。

LeetCode题解盲人买袜子。

他们都各自买了两对黑袜和两对白袜,八对袜子的布质、大小完全相同,而每对袜子都有一张商标纸连着。两位盲人不小心将八对袜子混在一起。他们每人怎样才能取回黑袜和白袜各两对呢?题解:暴力破解, 把袜子都拆开 一人一只 哈哈

LeetCode题解白石搭白塔

输入黑块和白块的数量,用输入的方块数目建塔,输出最大高度和种数,两种方法至少一层颜色不同才能算不同的方法塔满足下列要求:1. 塔底层块数和高度数值相同,逐层递减1,最高层为12. 每层颜色相同

LeetCode题解分鸡块

外卖鸡块分别有 4,6,12 块, 每 固定块数不能分开装, 用户给一个数字, 要求返回满足用户订单(可以等于也可以大于)的最少的盒数的组合