algorithm-base/animation-simulation/数据结构和算法/逆序对问题.md

136 lines
6.3 KiB
Java
Raw Normal View History

2021-07-23 15:44:19 +00:00
> 如果阅读时发现错误或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈
2021-03-20 08:30:29 +00:00
>
> 感谢支持该仓库会一直维护希望对各位有一丢丢帮助
>
2021-07-23 15:44:19 +00:00
> 另外希望手机阅读的同学可以来我的 <u>[**公众号袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)</u> 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击<u>[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)</u>进入。
2021-03-20 08:30:29 +00:00
2021-03-20 08:44:27 +00:00
#### [剑指 offer 51 数组中的逆序对](https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof)
2021-03-20 07:58:25 +00:00
逆序对在数组中的两个数字如果前面一个数字大于后面的数字则这两个数字组成一个逆序对见下图
![逆序对](https://cdn.jsdelivr.net/gh/tan45du/test1@master/20210122/逆序对.2p9sfhlbkaw0.png)
2021-07-23 15:44:19 +00:00
是不是很容易理解因为数组是无序的当较大的数出现在较小数前面的时候它俩则可以组成逆序对因为数组的有序度+逆序度= n (n-1) / 2逆序对个数 = 数组的逆序度有序对个数 = 数组的有序度所以我们知道有序对个数的话也能得到逆序对的个数另外我们如何通过归并排序来计算逆序对个数呢
2021-03-20 07:58:25 +00:00
关键点在我们的**归并过程中**我们先来看下归并过程中是怎么计算逆序对个数的见下图
![逆序对举例](https://cdn.jsdelivr.net/gh/tan45du/test1@master/20210122/微信截图_20210212200744.1upng86ndbr4.png)
2021-07-23 15:44:19 +00:00
我们来拆解下上图我们此时 temp1 指向元素为 6temp2 指向元素为 2, nums[temp1] > temp[temp2]则此时我们需要将 temp2 指向的元素存入临时数组中又因为每个小集合中的元素都是有序的所以 temp1 后面的元素也一定大于 2那么我们就可以根据 temp1 的索引得出逆序对中包含 2 的逆序对个数则是 mid - temp + 1
2021-03-20 07:58:25 +00:00
好啦这个题目你已经会做啦下面我们一起来做下吧
**题目描述**
在数组中的两个数字如果前面一个数字大于后面的数字则这两个数字组成一个逆序对输入一个数组求出这个数组中的逆序对的总数
**示例 1:**
> 输入: [7,5,6,4]
> 输出: 5
**题目解析**
2021-07-23 15:44:19 +00:00
各位如果忘记归并排序的话可以再看一下咱们之前的文章回顾一下 [归并排序详解](https://mp.weixin.qq.com/s/YK43J73UNFRjX4r0vh13ZA)这个题目我们仅仅在归并排序的基础上加了一行代码。那就是在归并过程时nums[temp2] < nums[temp1] 时统计个数。下面我们直接看代码吧。
2021-03-20 07:58:25 +00:00
**题目代码**
Java Code:
2021-03-20 07:58:25 +00:00
```java
class Solution {
//全局变量
2021-07-23 15:44:19 +00:00
private int count;
2021-03-20 07:58:25 +00:00
public int reversePairs(int[] nums) {
2021-07-23 15:44:19 +00:00
count = 0;
2021-03-20 07:58:25 +00:00
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 index = 0;
int temp1 = left, temp2 = mid+1;
while (temp1 <= mid && temp2 <= right) {
2021-07-23 15:44:19 +00:00
2021-03-20 07:58:25 +00:00
if (nums[temp1] <= nums[temp2]) {
temparr[index++] = nums[temp1++];
} else {
//增加的一行代码,用来统计逆序对个数
count += (mid - temp1 + 1);
temparr[index++] = nums[temp2++];
}
}
2021-07-23 15:44:19 +00:00
2021-03-20 07:58:25 +00:00
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);
}
}
```
Python Code:
```python
from typing import List
class Solution:
count = 0
def reversePairs(self, nums: List[int])->int:
self.count = 0
self.mergeSort(nums, 0, len(nums) - 1)
return self.count
def mergeSort(self, arr: List[int], left: int, right: int):
if left < right:
mid = left + ((right - left) >> 1)
self.mergeSort(arr, left, mid)
self.mergeSort(arr, mid + 1, right)
2021-07-23 15:44:19 +00:00
self.merge(arr, left, mid, right)
# 归并
def merge(self, arr: List[int], left: int, mid: int, right: int):
# 第一步定义一个新的临时数组
temparr = [0] * (right - left + 1)
temp1 = left
temp2 = mid + 1
index = 0
# 对应第二步比较每个指针指向的值小的存入大集合
while temp1 <= mid and temp2 <= right:
if arr[temp1] <= arr[temp2]:
temparr[index] = arr[temp1]
index += 1
temp1 += 1
else:
self.count += (mid - temp1 + 1)
temparr[index] = arr[temp2]
index += 1
temp2 += 1
# 对应第三步将某一集合的剩余元素存到大集合中
if temp1 <= mid:
temparr[index: index + mid - temp1 + 1] = arr[temp1: temp1 + mid - temp1 + 1]
2021-07-23 15:44:19 +00:00
if temp2 <= right:
temparr[index: index + right - temp2 + 1] = arr[temp2: temp2 + right - temp2 + 1]
2021-07-23 15:44:19 +00:00
# 将大集合的元素复制回原数组
arr[left: left + right- left + 1] = temparr[0: right - left + 1]
```
2021-03-20 07:58:25 +00:00
好啦这个题目我们就解决啦哦对大家也可以顺手去解决下这个题目leetcode 912 排序数组这个题目大家可以用来练手因为有些排序算法是面试高频考点所以大家可以防止遗忘多用这个题目进行练习防止手生下面则是我写文章时代码的提交情况冒泡排序怎么优化都会超时其他排序算法倒是都可以通过
![排序](https://cdn.jsdelivr.net/gh/tan45du/test1@master/20210122/排序.1unok1gcygtc.png)
好啦下面我们继续做一个题目吧也完全可以用归并排序解决稍微加了一丢丢代码但是也是很好理解的感谢支持