java面试题之数组中的逆序对
作者:水的化合物的专栏 发布时间:2021-08-05 10:51:02
题目:在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数
例如在数组{7,5,6,4}中,一共存在5对逆序对,分别是{7,6},{7,5},{7,4},{6,4},{5,4}。
看到这个题目,我们的第一反应就是顺序扫描整个数组。每扫描到一个数组的时候,逐个比较该数字和它后面的数字的大小。如果后面的数字比它小,则这两个数字就组成一个逆序对。假设数组中含有n个数字。由于每个数字都要和O(n)个数字做比较,因此这个算法的时间复杂度为O(n2)。我们尝试找找更快的算法。
我们以数组{7,5,6,4}为例来分析统计逆序对的过程,每次扫描到一个数字的时候,我们不能拿它和后面的每一个数字做比较,否则时间复杂度就是O(n2)因此我们可以考虑先比较两个相邻的数字。
如下图所示,我们先把数组分解称两个长度为2的子数组,再把这两个子数组分别茶城两个长度为1的子数组。接下来一边合并相邻的子数组,一边统计逆序对的数目。在第一对长度为1的子数组{7},{5}中7大于5,因此{7,5}组成一个逆序对。同样在第二对长度为1的子数组{6},{4}中也有逆序对{6,4}。由于我们已经统计了这两队子数组内部逆序对,因此需要把这两对子数组排序,以免在以后的统计过程中再重复统计。
接下来我们统计两个长度为2的子数组之间的逆序对。
我们先用两个指针分别指向两个子数组的末尾,并每次比较两个指针指向的数字。如果第一个子数组中的数字大于第二个子数组中的数字,则构成逆序对,并且逆序对的数目等于第二个子数组中的剩余数字的个数。如果第一个数组中的数字小于或等于第二个数组中的数字,则不构成逆序对。每一次比较的时候,我们都把较大的数字从后往前复制到一个辅助数组中去,确保辅助数组中的数字是递增排序的。在把较大的数字复制到数组之后,把对应的指针向前移动一位,接着来进行下一轮的比较。
经过前面详细的讨论,我们可以总结出统计逆序对的过程:先把数组分隔成子数组,先统计出子数组内部的逆序对的数目,然后再统计出两个相邻子数组之间的逆序对的数目。在统计逆序对的过程中,还需要对数组进行排序。如果对排序算法很熟悉,我们不难发现这个排序的过程就是归并排序。
static int count = 0;
// 将有二个有序数列a[first...mid]和a[mid...last]合并。
static void mergearray(int a[], int first, int mid, int last, int temp[]) {
int i = first, j = mid + 1;
int m = mid, n = last;
int k = 0;
while (i <= m && j <= n) {
if (a[i] > a[j]) {
// 左数组比右数组大
temp[k++] = a[j++];
// 因为如果a[i]此时比右数组的当前元素a[j]大,
// 那么左数组中a[i]后面的元素就都比a[j]大
// 【因为数组此时是有序数组】
count += mid - i + 1;
} else {
temp[k++] = a[i++];
}
}
while (i <= m) {
temp[k++] = a[i++];
}
while (j <= n) {
temp[k++] = a[j++];
}
for (i = 0; i < k; i++)
a[first + i] = temp[i];
}
static void mergesort(int a[], int first, int last, int temp[]) {
if (first < last) {
int mid = (first + last) / 2;
mergesort(a, first, mid, temp); // 左边有序
mergesort(a, mid + 1, last, temp); // 右边有序
mergearray(a, first, mid, last, temp); // 再将二个有序数列合并
}
}
static void mergeSort(int a[]) {
int[] p = new int[a.length];
mergesort(a, 0, a.length - 1, p);
}
来源:https://blog.csdn.net/abc7845129630/article/details/52740746


猜你喜欢
- 这篇文章主要介绍了Java方法参数传递机制原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可
- java与JSON数据的转换实例详解JSON与JAVA数据的转换(JSON 即 JavaScript Object Natation,它是一
- 在阿里开发手册的建表规约中有说明,数据库表中应该都要有create_time、update_time字段;那么在开发中,对于这些共有字段的处
- IO流基本概念IO流用来处理设备之间的数据传输Java对数据的操作是通过流的方式Java用于操作流的对象都是在IO包上流按操作数
- 本文实例讲述了C#实现用于操作wav声音文件的类。分享给大家供大家参考。具体如下:有了这个C#类,我们可以很轻易的调用本地wav文件进行同步
- Android 登录处理简单实例今天整理一下之前在项目中写的关于某些界面需要登录判断处理。这里整理了一个简易的 Demo 模拟一下 登录情况
- 本文主要包括以下内容:使用Xfermode设置圆角图片使用BitmapShader设置圆角图片滑动旋转缩放的bimp图片图片颜色处理(滑动)
- 简介平时包括之前的例子大量是基于TouchListener如:onClick这种一类的事件。今天给大家带来的是TouchListener与O
- web.xml中设置:<servlet> <servlet-name>DisplayChart</servle
- 本文主要记录JAVA中对象的初始化过程,包括实例变量的初始化和类变量的初始化以及final关键字对初始化的影响。另外,还讨论了由于继承原因,
- 什么是“异步调用”?“异步调用”对应的是“同步调用”,同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行
- 在这里就分享两条开发中曾经忽略的问题:1、Union(联合体)的字节对齐先看代码:#pragma pack(4)struct com{&nb
- import java.awt.AlphaComposite;import java.awt.Color;import java.awt.F
- 配置Thymeleaf的模板路径众所周知,Thymeleaf的模板文件默认是在项目文件夹的src\main\resources\templa
- 一、模拟业务需求假设我们现在需要在我们的系统中导入一批关于学生信息的Excel的数据,其主要的信息有:学号、姓名、年龄、性别等等,在导入系统
- jsoup 是一款 Java 的 HTML 解析器,可直接解析某个 URL 地址、HTML 文本内容。它提供了一套非常省力的 API,可通过
- 本文实例为大家分享了unity通过Mesh网格绘制球体的具体代码,供大家参考,具体内容如下接着上一篇文章说:球体public class 球
- 数组作为函数的参数传递首地址。A进行修改,a同时也会进行修改。数组参数的传递机制来源:https://blog.csdn.net/weixi
- * String类是不可变类,只要对String进行修改,都会导致新的对象生成。* StringBuffer和StringBuilder都是
- 一、获取某年某月的天数1.在实现日期类的过程中,日期加减天数的应用场景一定会频繁使用到这个函数接口,因为加减天数会使得月份发生变化,可能增月