This commit is contained in:
chefyuan 2021-03-19 21:08:47 +08:00
parent b5db9275ab
commit fb32699a2d
3 changed files with 109 additions and 96 deletions

View File

@ -7,10 +7,24 @@
## 数据结构和算法(前置知识)
[【动画模拟】字符串匹配 BF 算法](https://github.com/chefyuan/algorithm-base/blob/main/gif-algorithm/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/BF%E7%AE%97%E6%B3%95.md)
- ### [【动画模拟】字符串匹配 BF 算法](https://github.com/chefyuan/algorithm-base/blob/main/gif-algorithm/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/BF%E7%AE%97%E6%B3%95.md)
[【动画模拟】字符串匹配 BM 算法](https://github.com/chefyuan/algorithm-base/blob/main/gif-algorithm/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/BM.md)
- ### [【动画模拟】字符串匹配 BM 算法](https://github.com/chefyuan/algorithm-base/blob/main/gif-algorithm/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/BM.md)
[【动画模拟】字符串匹配 KMP 算法](https://github.com/chefyuan/algorithm-base/blob/main/gif-algorithm/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/KMP.md)
- ### [【动画模拟】字符串匹配 KMP 算法](https://github.com/chefyuan/algorithm-base/blob/main/gif-algorithm/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/KMP.md)
[【动画模拟】哈希表详解](https://github.com/chefyuan/algorithm-base/blob/main/gif-algorithm/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/Hash%E8%A1%A8%E7%9A%84%E9%82%A3%E4%BA%9B%E4%BA%8B.md)
- ### [【动画模拟】冒泡排序](https://github.com/chefyuan/algorithm-base/blob/main/gif-algorithm/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F.md)
- ### [【动画模拟】简单选择排序](https://github.com/chefyuan/algorithm-base/blob/main/gif-algorithm/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E7%AE%80%E5%8D%95%E9%80%89%E6%8B%A9%E6%8E%92%E5%BA%8F.md)
- ### [【动画模拟】插入排序](https://github.com/chefyuan/algorithm-base/blob/main/gif-algorithm/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E7%9B%B4%E6%8E%A5%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F.md)
- ### [【动画模拟】希尔排序](https://github.com/chefyuan/algorithm-base/blob/main/gif-algorithm/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E5%B8%8C%E5%B0%94%E6%8E%92%E5%BA%8F.md)
- ### [【动画模拟】归并排序](https://github.com/chefyuan/algorithm-base/blob/main/gif-algorithm/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F.md)
- ### [【动画模拟】快速排序](https://github.com/chefyuan/algorithm-base/blob/main/gif-algorithm/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F.md)
- ### [【动画模拟】堆排序](https://github.com/chefyuan/algorithm-base/blob/main/gif-algorithm/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E5%A0%86%E6%8E%92%E5%BA%8F.md)
- ### [【动画模拟】哈希表详解,万字长文](https://github.com/chefyuan/algorithm-base/blob/main/gif-algorithm/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/Hash%E8%A1%A8%E7%9A%84%E9%82%A3%E4%BA%9B%E4%BA%8B.md)

View File

@ -0,0 +1,91 @@
#### 翻转对
**题目描述**
给定一个数组 nums ,如果 i < j nums[i] > 2*nums[j] 我们就将 (i, j) 称作一个重要翻转对。
你需要返回给定数组中的重要翻转对的数量。
示例 1:
> 输入: [1,3,2,3,1]
> 输出: 2
示例 2:
> 输入: [2,4,3,5,1]
> 输出: 3
**题目解析**
我们理解了逆序对的含义之后,题目理解起来完全没有压力的,这个题目第一想法可能就是用暴力法解决,但是会超时,所以我们有没有办法利用归并排序来完成呢?
我们继续回顾一下归并排序的归并过程,两个小集合是有序的,然后我们需要将小集合归并到大集合中,则我们完全可以在归并之前,先统计一下翻转对的个数,然后再进行归并,则最后排序完成之后自然也就得出了翻转对的个数。具体过程见下图。
![翻转对](https://cdn.jsdelivr.net/gh/tan45du/test1@master/20210122/微信截图_20210214121010.50g9z0xgda80.png)
此时我们发现 6 > 2 * 2所以此时是符合情况的因为小数组是单调递增的所以 6 后面的元素都符合条件,所以我们 count += mid - temp1 + 1则我们需要移动紫色指针判断后面是否还存在符合条件的情况。
![翻转对](https://cdn.jsdelivr.net/gh/tan45du/test1@master/20210122/微信截图_20210214121711.77crljdzra00.png)
我们此时发现 6 = 3 * 2不符合情况因为小数组都是完全有序的所以我们可以移动红色指针看下后面的数有没有符合条件的情况。这样我们就可以得到翻转对的数目啦。下面我们直接看动图加深下印象吧
![](https://img-blog.csdnimg.cn/20210317192545806.gif#pic_center)
是不是很容易理解啊,那我们直接看代码吧,仅仅是在归并排序的基础上加了几行代码。
```java
class Solution {
private int count;
public int reversePairs(int[] nums) {
count = 0;
merge(nums, 0, nums.length - 1);
return count;
}
public void merge(int[] nums, int left, int right) {
if (left < right) {
int mid = left + ((right - left) >> 1);
merge(nums, left, mid);
merge(nums, mid + 1, right);
mergeSort(nums, left, mid, right);
}
}
public void mergeSort(int[] nums, int left, int mid, int right) {
int[] temparr = new int[right - left + 1];
int temp1 = left, temp2 = mid + 1, index = 0;
//计算翻转对
while (temp1 <= mid && temp2 <= right) {
//这里需要防止溢出
if (nums[temp1] > 2 * (long) nums[temp2]) {
count += mid - temp1 + 1;
temp2++;
} else {
temp1++;
}
}
//记得归位,我们还要继续使用
temp1 = left;
temp2 = mid + 1;
//归并排序
while (temp1 <= mid && temp2 <= right) {
if (nums[temp1] <= nums[temp2]) {
temparr[index++] = nums[temp1++];
} else {
temparr[index++] = nums[temp2++];
}
}
//照旧
if (temp1 <= mid) System.arraycopy(nums, temp1, temparr, index, mid - temp1 + 1);
if (temp2 <= right) System.arraycopy(nums, temp2, temparr, index, right - temp2 + 1);
System.arraycopy(temparr, 0, nums, left, right - left + 1);
}
}
```

View File

@ -86,95 +86,3 @@ class Solution {
好啦,下面我们继续做一个题目吧,也完全可以用归并排序解决,稍微加了一丢丢代码,但是也是很好理解的。
#### 翻转对
**题目描述**
给定一个数组 nums ,如果 i < j nums[i] > 2*nums[j] 我们就将 (i, j) 称作一个重要翻转对。
你需要返回给定数组中的重要翻转对的数量。
示例 1:
> 输入: [1,3,2,3,1]
> 输出: 2
示例 2:
> 输入: [2,4,3,5,1]
> 输出: 3
**题目解析**
我们理解了逆序对的含义之后,题目理解起来完全没有压力的,这个题目第一想法可能就是用暴力法解决,但是会超时,所以我们有没有办法利用归并排序来完成呢?
我们继续回顾一下归并排序的归并过程,两个小集合是有序的,然后我们需要将小集合归并到大集合中,则我们完全可以在归并之前,先统计一下翻转对的个数,然后再进行归并,则最后排序完成之后自然也就得出了翻转对的个数。具体过程见下图。
![翻转对](https://cdn.jsdelivr.net/gh/tan45du/test1@master/20210122/微信截图_20210214121010.50g9z0xgda80.png)
此时我们发现 6 > 2 * 2所以此时是符合情况的因为小数组是单调递增的所以 6 后面的元素都符合条件,所以我们 count += mid - temp1 + 1则我们需要移动紫色指针判断后面是否还存在符合条件的情况。
![翻转对](https://cdn.jsdelivr.net/gh/tan45du/test1@master/20210122/微信截图_20210214121711.77crljdzra00.png)
我们此时发现 6 = 3 * 2不符合情况因为小数组都是完全有序的所以我们可以移动红色指针看下后面的数有没有符合条件的情况。这样我们就可以得到翻转对的数目啦。下面我们直接看动图加深下印象吧
![](https://img-blog.csdnimg.cn/20210317192545806.gif#pic_center)
是不是很容易理解啊,那我们直接看代码吧,仅仅是在归并排序的基础上加了几行代码。
```java
class Solution {
private int count;
public int reversePairs(int[] nums) {
count = 0;
merge(nums, 0, nums.length - 1);
return count;
}
public void merge(int[] nums, int left, int right) {
if (left < right) {
int mid = left + ((right - left) >> 1);
merge(nums, left, mid);
merge(nums, mid + 1, right);
mergeSort(nums, left, mid, right);
}
}
public void mergeSort(int[] nums, int left, int mid, int right) {
int[] temparr = new int[right - left + 1];
int temp1 = left, temp2 = mid + 1, index = 0;
//计算翻转对
while (temp1 <= mid && temp2 <= right) {
//这里需要防止溢出
if (nums[temp1] > 2 * (long) nums[temp2]) {
count += mid - temp1 + 1;
temp2++;
} else {
temp1++;
}
}
//记得归位,我们还要继续使用
temp1 = left;
temp2 = mid + 1;
//归并排序
while (temp1 <= mid && temp2 <= right) {
if (nums[temp1] <= nums[temp2]) {
temparr[index++] = nums[temp1++];
} else {
temparr[index++] = nums[temp2++];
}
}
//照旧
if (temp1 <= mid) System.arraycopy(nums, temp1, temparr, index, mid - temp1 + 1);
if (temp2 <= right) System.arraycopy(nums, temp2, temparr, index, right - temp2 + 1);
System.arraycopy(temparr, 0, nums, left, right - left + 1);
}
}
```
###