diff --git a/README.md b/README.md index 0d39d1e..8bc4b35 100644 --- a/README.md +++ b/README.md @@ -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) \ No newline at end of file +- ### [【动画模拟】冒泡排序](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) \ No newline at end of file diff --git a/gif-algorithm/数据结构和算法/翻转对.md b/gif-algorithm/数据结构和算法/翻转对.md new file mode 100644 index 0000000..a32d86f --- /dev/null +++ b/gif-algorithm/数据结构和算法/翻转对.md @@ -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); + } +} +``` + diff --git a/gif-algorithm/数据结构和算法/逆序对问题.md b/gif-algorithm/数据结构和算法/逆序对问题.md index b09cba8..145e9b1 100644 --- a/gif-algorithm/数据结构和算法/逆序对问题.md +++ b/gif-algorithm/数据结构和算法/逆序对问题.md @@ -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); - } -} -``` - -### \ No newline at end of file