题目:在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。例如,有一个数组为Array[0..n] 其中有元素a[i],a[j].如果 当i<j时,a[i]>a[j],那么我们就称(a[i],a[j])为一个逆序对。在数组{7,5,6,4}中一共存在5对逆序对,分别是(7,6),(7,5),(7,4),(6,4),(5,4)。

参考文献

排序算法汇总->归并排序

解题思路

看到这样的题目,最简单的想法就是遍历每一个元素,让其与后面的元素对比,如果大于则count++,但是这样的时间复杂度是o(n2)。这题有更好的解决方法,时间复杂度只需要o(nlogn)。其实这道题目的思路跟归并排序差不多,求逆序对的过程就是一个求归并排序的过程,在求出逆序对以后,原数组变得有序,是通过归并排序得到的。

(1)总体的意思就是将数组分成两段,首先求段内的逆序对数量,比如下面两段代码就是求左右两端数组段内的逆序对数量

inversions+=InversePairsCore(arry,start,mid,temp);//找左半段的逆序对数目
inversions+=InversePairsCore(arry,mid+1,end,temp);//找右半段的逆序对数目

(2)然后求段间的逆序对数量,如下面的代码

inversions+=MergeArray(arry,start,mid,end,temp);//在找完左右半段逆序对以后两段数组有序,然后找两段之间的逆序对。最小的逆序段只有一个元素。

(3)然后在求段间逆序对的时候,我们分为arry[start...mid]和arry[mid+1...end],然后设置两个指针ij分别指向两段数组的末尾元素,也就是i=mid,j=end。然后比较arry[i]和arry[j],

  1. 如果arry[i]>arry[j],因为两段数组都是有序的,所以arry[i]>arry[mid+1...j],这些都是逆序对,我们统计出的逆序对为j-(mid+1)+1=j-mid。并且将大数arry[i]放入临时数组temp[]当中,i往前移动
  2. 如果arry[i]<arry[j],则将大数arry[j]放入temp[]中,j往前移。

完整实现代码

View Code

#include<iostream>
#include<stdlib.h>
using namespace std;void printArray(int arry[],int len)
{for(int i=0;i<len;i++)cout<<arry[i]<<" ";cout<<endl;
}
int MergeArray(int arry[],int start,int mid,int end,int temp[])//数组的归并操作
{//int leftLen=mid-start+1;//arry[start...mid]左半段长度//int rightLlen=end-mid;//arry[mid+1...end]右半段长度int i=mid;int j=end;int k=0;//临时数组末尾坐标int count=0;//设定两个指针ij分别指向两段有序数组的头元素,将小的那一个放入到临时数组中去。while(i>=start&&j>mid){if(arry[i]>arry[j]){temp[k++]=arry[i--];//从临时数组的最后一个位置开始排序count+=j-mid;//因为arry[mid+1...j...end]是有序的,如果arry[i]>arry[j],那么也大于arry[j]之前的元素,从a[mid+1...j]一共有j-(mid+1)+1=j-mid
            }else{temp[k++]=arry[j--];}}cout<<"调用MergeArray时的count:"<<count<<endl;while(i>=start)//表示前半段数组中还有元素未放入临时数组
    {temp[k++]=arry[i--];}while(j>mid){temp[k++]=arry[j--];}//将临时数组中的元素写回到原数组当中去。for(i=0;i<k;i++)arry[end-i]=temp[i];printArray(arry,8);//输出进过一次归并以后的数组,用于理解整体过程return count;}int InversePairsCore(int arry[],int start,int end,int temp[])
{int inversions = 0;  if(start<end){int mid=(start+end)/2;inversions+=InversePairsCore(arry,start,mid,temp);//找左半段的逆序对数目inversions+=InversePairsCore(arry,mid+1,end,temp);//找右半段的逆序对数目inversions+=MergeArray(arry,start,mid,end,temp);//在找完左右半段逆序对以后两段数组有序,然后找两段之间的逆序对。最小的逆序段只有一个元素。
    }    return inversions;
}int InversePairs(int arry[],int len)
{int *temp=new int[len];int count=InversePairsCore(arry,0,len-1,temp);delete[] temp;return count;
}void main()
{//int arry[]={7,5,6,4};int arry[]={1,3,7,8,2,4,6,5};int len=sizeof(arry)/sizeof(int);//printArray(arry,len);int count=InversePairs(arry,len);//printArray(arry,len);//cout<<count<<endl;system("pause");
}

输出结果:

调用MergeArray时的count:0
1 3 7 8 2 4 6 5
调用MergeArray时的count:0
1 3 7 8 2 4 6 5
调用MergeArray时的count:0
1 3 7 8 2 4 6 5
调用MergeArray时的count:0
1 3 7 8 2 4 6 5
调用MergeArray时的count:1//这是因为上面65之间有段内的逆序对
1 3 7 8 2 4 5 6
调用MergeArray时的count:0
1 3 7 8 2 4 5 6
调用MergeArray时的count:9//这里全部都是段间的逆序对,(3,2),(7,2),(7,4),(7,5),(7,6),(8,2),(8,4),(8,5),(8,6),一共有九个
1 2 3 4 5 6 7 8
逆序对数量:10

面试题36:数组中的逆序对相关推荐

  1. 剑指offer面试题[36]-数组中的逆序对

    题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P.并将P对1000000007取模的结果输出. 即输出P%1000 ...

  2. c语言数组求逆序对,LeetCode 面试题51. 数组中的逆序对

    面试题51. 数组中的逆序对 题目来源:https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof/ 题目 在数组中的两个数字,如果 ...

  3. [剑指offer][JAVA]面试题[51][数组中的逆序对][归并排序]

    [问题描述]面试题51.数组中的逆序对 (困难) 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. 示例 1:输入: [7, ...

  4. 【剑指offer-Java版】36数组中的逆序对

    数组中的逆序对:归并排序的另类应用 数组中的逆序对:给定的数组,如果两个数字中前面一个数字大于后面的一个,那么称为一个逆序对,数组中所有满足此关系的逆序对总数就是这个数组的逆序对 此处的实现并不优雅, ...

  5. 剑指Offer - 面试题51. 数组中的逆序对(归并排序,求逆序对)

    1. 题目 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. 示例 1: 输入: [7,5,6,4] 输出: 5限制: 0 ...

  6. 面试题51. 数组中的逆序对

    可以和面试官对一下是否需要修改原数组 题解: https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof/solution/shu- ...

  7. 【重点】剑指offer——面试题36:数组中的逆序对

    剑指offer--面试题36:数组中的逆序对 Solution1: 20180905整理 参考网址:https://www.nowcoder.com/profile/4474567/codeBookD ...

  8. C++版 - 剑指Offer 面试题36:数组中的逆序对及其变形(Leetcode 315. Count of Smaller Numbers After Self)题解

    剑指Offer 面试题36:数组中的逆序对 题目:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. 例如, 在数组{7,5, ...

  9. 【算法题目】数组中的逆序对

    题目来源:<剑指offer>面试题36 题目:在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这两个数组中的逆序对的总数.例如数组{7,5, ...

最新文章

  1. Android Studio导入Eclipse项目的两种方法
  2. Linux下常用的命令
  3. Could not open Hibernate Session for transaction;
  4. BZOJ3224普通平衡树
  5. 解析PHP实现多进程并行执行脚本
  6. 数据库启动提示: ORA-27102: out of memory
  7. 最长有效括号—leetcode32
  8. 发布订阅之topics
  9. hdu 1800 (map)
  10. Netty框架中的@Skip使用说明
  11. 最全的微信小程序代码大全
  12. Java之JDBC安装、使用详解(2021最新!)
  13. mysql 导出 客户端_Web基础配置篇(四): Mysql的配置及使用
  14. 4G模块配置、概念、调试记录
  15. compile函数使用
  16. IOS学习笔记-加速度传感器(重力感应)-UIAccelerometer
  17. 百度地图API基本使用(一)
  18. 【开发环境】Windows环境下Python开发环境 Pycharm Anaconda安装配置(无错完整)
  19. 织梦仿微信公众号文章页面html,织梦DEDECMS微信内容页插件
  20. 人力资源后台管理系统之合同—— 电子签章功能

热门文章

  1. 电子科大计算机调试,电子科大计算机学院 汇编语言程序设计 实验报告 99分精品版.doc...
  2. 查询hive表_大数据中Hive与HBase的区别与联系
  3. centos7 RPM命令安装操作
  4. 求矩阵中各列数字的和
  5. 采用成员函数和友元函数计算给定两个坐标点之间的距离
  6. php 应用程序错误,系统化PHP中的Web应用程序的错误代码?
  7. eventsource前台怎么接收一个对象数据_Java开发经验总结篇(1)——数据保存的整洁方法...
  8. oracle segment undo_Oracle Undo工作原理
  9. “数据资产化探索”专题
  10. 【2016年第4期】欧盟数据可携权评析