From b88256f07f99d48352fa58945dd3f6a29293cd67 Mon Sep 17 00:00:00 2001 From: lucifer Date: Mon, 20 Jan 2020 10:27:27 +0800 Subject: [PATCH] feat: #493 --- README.md | 1 + problems/493.reverse-pairs.md | 120 ++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 problems/493.reverse-pairs.md diff --git a/README.md b/README.md index a3fa2c2a9..c82cdc297 100644 --- a/README.md +++ b/README.md @@ -255,6 +255,7 @@ leetcode 题解,记录自己的 leetcode 解题之路。 - [0295.find-median-from-data-stream](./problems/295.find-median-from-data-stream.md) 🆕 - [0301.remove-invalid-parentheses](./problems/301.remove-invalid-parentheses.md) - [0460.lfu-cache](./problems/460.lfu-cache.md) 🆕 +- [0493.reverse-pairs](./problems/493.reverse-pairs.md) 🆕 - [1168.optimize-water-distribution-in-a-village](./problems/1168.optimize-water-distribution-in-a-village-cn.md) 🆕 ### 数据结构与算法的总结 diff --git a/problems/493.reverse-pairs.md b/problems/493.reverse-pairs.md new file mode 100644 index 000000000..0470c9720 --- /dev/null +++ b/problems/493.reverse-pairs.md @@ -0,0 +1,120 @@ +## 题目地址(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: + +```python +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): + +```python +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: + +```python +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"](https://leetcode.com/problems/reverse-pairs/discuss/97268/General-principles-behind-problems-similar-to-%22Reverse-Pairs%22)