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

95 lines
4.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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