java面试题之数组中的逆序对

题目:在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数

例如在数组{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);
 }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 面试题:Java 实现查找旋转数组的最小数字

    在算法面试中,面试官总是喜欢围绕链表.排序.二叉树.二分查找来做文章,而大多数人都可以跟着专业的书籍来做到倒背如流.而面试官并不希望招收的是一位记忆功底很好,但不会活学活用的程序员.所以学会数学建模和分析问题,并用合理的算法或数据结构来解决问题相当重要. 面试题:打印出旋转数组的最小数字 题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如数组 {3,4,5,1,2} 为数组 {1,2,3,4,5} 的一个旋转,该

  • 从java面试题了解你所模糊的数组

    前言 数组,最基础的一种数据结构.尽管看起来非常的简单.基础,但是面试往往逃不过它. 特性 下标从0开始 线性表数据结构 一组连续的内存空间来存储一组具有相同类型的数据 如何实现随机访问 从上面的特性可以得到几个关键词: 1.线性表.线性表就是数据排成一条线一样的结构.只有前后两个关系.比如:数组.链表.栈.队列等: 2.连续的内存空间和相同类型的数据.所以你所回答的不适合insert.delete就是基于这个原因,为了保持它的连续性. 数组根据下标实现随机访问数组元素的公式: a[i]_add

  • 浅谈JAVA实现选择排序,插入排序,冒泡排序,以及两个有序数组的合并

    一直到大四才开始写自己的第一篇博客,说来实在有点羞愧.今天写了关于排序的算法题,有插入排序,冒泡排序,选择排序,以下贴上用JAVA实现的代码: public class test5 { public static void print(int []array) //输出数组方法 { for(int i=0;i<array.length;i++) System.out.print(" "+array[i]); } public static void selectsort(int

  • java利用数组随机抽取幸运观众

    本文实例为大家分享了java利用数组随机抽取幸运观众的具体代码,供大家参考,具体内容如下 思想: 首先将所有观众姓名生成数组,然后获取数组元素的总数量,再在数组元素中随机抽取元素的下标,根据元素的下标得到幸运观众的名字. import java.awt.BorderLayout; import java.awt.EventQueue; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.border.E

  • java数据结构和算法中数组的简单入门

    一直都对这一块没有什么想法,加上不怎么理解,只是懂个大概:最近突然感觉对数据结构和算法这块有点儿兴趣,决定还是尽量详细的看看这些结构和算法: 话说什么事数据结构和算法呢?现在我也说不上来,等我学的差不多了再来总结吧! 我随意借了一张图,所谓的数据结构就是下面这些,我们一个一个的慢慢看(玛德,好多...) 1.数组的基本用法 对于数组应该很熟悉了,最开始学完java八种基本类型之后下一个就是学的数组,数组最大的特点就是除了Object数组之外,其他的数组只能存放同一种数据类型,而且我们一开始指定数

  • java集合与数组的相同点和不同点

    数组: 数组可以用来保存多个基本数据类型的数据,也可以用来保存多个对象. 数组的长度是不可改变的,一旦初始化数组时就指定了数组的长度(无论是静态初始化还是动态初始化). 数组无法保存具有映射关系的数据. 集合: 集合是只用于存储数量不等的对象. 集合的长度是可变的. 集合可以保存具有映射关系的数据. 相同点: 数组和集合类同是容器. 不同点: 数组的长度是固定的,集合的长度是可变的. 数组只能存储同类型的对象,集合可以存储不同类型的对象. 集合只能存储对象不能存储基本类型 总结 以上就是这篇文章

  • java面试题之数组中的逆序对

    题目:在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数 例如在数组{7,5,6,4}中,一共存在5对逆序对,分别是{7,6},{7,5},{7,4},{6,4},{5,4}. 看到这个题目,我们的第一反应就是顺序扫描整个数组.每扫描到一个数组的时候,逐个比较该数字和它后面的数字的大小.如果后面的数字比它小,则这两个数字就组成一个逆序对.假设数组中含有n个数字.由于每个数字都要和O(n)个数字做比较,因此这个算法的时间复杂度为

  • java简单实现数组中的逆序对

    题目描述: 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P.并将P对1000000007取模的结果输出. 即输出P%1000000007 解题思路: 一开始一头雾水,后面想到了使用归并排序的思想,其实有多少个逆序对,就是归并排序的时候,后面的数要超越前面多少个,嗯,好像不是很好说,要不然直接看代码吧.还要注意,题目当中说要输出取模的结果,这说明数据可能非常大,所以如果只是单纯的在最后取模的话可能还是无法避免数据太大的影

  • java实现数组中的逆序对

    在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对,例如在数组{7,5,6,4}中,一共存在5对逆序对,分别是{7,6},{7,5},{7,4},{6,4},{5,4}.输入一个数组,求出这个数组中的逆序对的总数P.并将P对1000000007取模的结果输出.,即输出P%1000000007. 代码 解法一 暴力简单低效,不会改变原数组 public static int inversePairs(int[] array) { if (array == null ||

  • Java实现删除排序数组中重复元素的方法小结【三种方法比较】

    本文实例讲述了Java实现删除排序数组中重复元素的方法.分享给大家供大家参考,具体如下: 题目描述: 给定一个排序数组,在原数组中删除重复出现的数字,使得每个元素只出现一次,并且返回新的数组的长度. 不要使用额外的数组空间,必须在原地没有额外空间的条件下完成. 一:通过ArrayList解决 时间复杂度和空间复杂度都为O(n) ArrayList<Integer> list = new ArrayList<Integer>(); // 去掉数组中重复的元素 public int r

  • Java编程实现统计数组中各元素出现次数的方法

    本文实例讲述了Java编程实现统计数组中各元素出现次数的方法.分享给大家供大家参考,具体如下: package javatest; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; public class NumOfEle { public static void main(String[] ar

  • java实现向有序数组中插入一个元素实例

    整理文档,搜刮出一个java实现向有序数组中插入一个元素,稍微整理精简一下做下分享 package cn.jbit.array; import java.util.*; public class Insert { public static void main(String[] args) { //字符排序 char[] chars = new char[9]; chars[0] = 'a'; chars[1] = 'c'; chars[2] = 'u'; chars[3] = 'b'; cha

  • java获取两个数组中不同数据的方法

    本文实例讲述了java获取两个数组中不同数据的方法.分享给大家供大家参考.具体实现方法如下: public static <T> List<T> compare(T[] t1, T[] t2) { List<T> list1 = Arrays.asList(t1); List<T> list2 = new ArrayList<T>(); for (T t : t2) { if (!list1.contains(t)) { list2.add(t)

  • java使用Hashtable过滤数组中重复值的方法

    本文实例讲述了java使用Hashtable过滤数组中重复值的方法.分享给大家供大家参考,具体如下: package org.eline.core.web.support; import java.util.Hashtable; /***************************** * * @author zdw * */ public class ObjectFilter { public static void main(String[] args) { // String 测试 S

  • java使用分隔符连接数组中每个元素的实例

    如下所示: double[] features3 = {1,2,3};//如果是基本类型需先转为对象 <span style="font-family:Arial;font-size:14px;">commons-lang3包可用</span> Double[] features4 = ArrayUtils.toObject(features3); public String listToString(List list, char separator) { r

  • java学习之一维数组中重复元素的去除

    目录 一.基本思路 二.步骤 1.设置判断数组Arr[ ] 2.继承数组newArr[ ]获取不重复元素 总结 一.基本思路 首先,假设一个一维数组arr[ ]={ 4, 3, 35, 3, 2, 4, 6, 3},其中有三个重复元素 3,4,3.要如何剔除呢,由于还没有涉猎到一些经典的调用,所以我选择了用新的数组newArr[ ]去继承原来数组中的不重复的元素,另外还需要一个判断数组Arr[ ],来判断arr[ ]中哪几个元素是重复的,才好去除掉. 二.步骤 1.设置判断数组Arr[ ] 代码

随机推荐