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

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

示例 1:

输入: [7,5,6,4]
输出: 5

限制:

0 <= 数组长度 <= 50000

归并排序简介:

    归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

  将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并(如下图)。

  归并排序时间复杂度为NlogN,仅次于快速排序(点击链接可看我之前发过的快排博文),为稳定排序算法,一般用于对总体无序,但是各子项相对有序的数列

                  

归并排序举例:

    如设有数列{6,202,100,301,38,8,1}

    初始状态:6,202,100,301,38,8,1

    第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;

    第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;

    第三次归并后:{1,6,8,38,100,202,301},比较次数:4;

    总的比较次数为:3+4+4=11;

    逆序对数为14对;

归并排序求逆序对数:具体思路是,在归并的过程中计算每个小区间的逆序对数,进而计算出大区间的逆序对数(也可以用 树状数组来求解)

代码解析:

 class Solution {
//归并排序:
int reversepairs = 0;//逆序对数
public int[] mergeSort(int[] nums, int left, int right){//归并排序函数
if (left == right)//如果左边界等于右边界,说明数组只有一个值,不用排序
return new int[] { nums[left] };
int mid = (right + left) / 2;//将数组分为两半 int[] leftArr = mergeSort(nums, left, mid); //左有序数组
int[] rightArr = mergeSort(nums, mid + 1, right); //右有序数组
int[] newNum = new int[leftArr.length + rightArr.length]; //新的有序数组 int m = 0, i = 0, j = 0;
//挨着挨着比较从左右两边的排好序的数组中从头开始比较,谁小就先放谁进新的有序空数组
while (i < leftArr.length && j < rightArr.length){//直到左右两个有序数组有一个的遍历下标超出该数组的序列尾部
if(leftArr[i] <= rightArr[j])//左序列的元素小,就把左序列的该元素放入新的空的有序数组中
newNum[m++] = leftArr[i++];
else{//右序列的元素小,就把右序列的该元素放入新的空的有序数组中
newNum[m++] = rightArr[j++];
reversepairs += leftArr.length - i;//左边序列数组中还有leftArr.length-i个元素大于rightArr[j],所以这也是该区间的逆序对数 }
}
while (i < leftArr.length)//如果左序列的元素还有剩余的元素没放进新的空数组中,就把左序列剩余元素放入新的空的有序数组中
newNum[m++] = leftArr[i++];
while (j < rightArr.length)//如果右序列的元素还有剩余的元素没放进新的空数组中,就把右序列剩余元素放入新的空的有序数组中
newNum[m++] = rightArr[j++];
return newNum;
}
public int reversePairs(int[] nums) {//入口函数
if(nums.length == 0)//如果给定的是个空数组,据题意返回0
return 0;
int[] newNums = mergeSort(nums, 0, nums.length - 1);//调用归并排序函数,返回一个有序的数组
return reversepairs;//返回逆序对数
}
}

    

最新文章

  1. T-SQL简单查询语句
  2. 【Java基础】并发
  3. [讨论] 这几天来封装Win7用户配置文件丢失的解决方法个人心得
  4. IOS中程序如何进行推送消息(本地推送,远程推送)
  5. Java IO2:RandomAccessFile
  6. java开发微信公众平台备忘
  7. 前端资源多个产品整站一键打包&amp;包版本管理(四)—— js&amp;css文件文件打包并生成哈希后缀,自动写入路径、解决资源缓存问题。
  8. OpenSSL 与 SSL 数字证书概念贴
  9. ABAP常用字符串处理
  10. 纯CSS3实现的图片滑块程序 效果非常酷
  11. meta常用标签总结
  12. 深度揭秘ES6代理Proxy
  13. 使用Docker部署Spring boot项目
  14. 【BZOJ3997】[TJOI2015]组合数学(动态规划)
  15. [Swift-2019力扣杯春季初赛]4. 从始点到终点的所有路径
  16. 高斯模糊的Java实现
  17. iOS如何在应用中添加图标更换功能
  18. 对象转Json时,Date类型格式化问题
  19. 十、K3 WISE 开发插件《SQL Profiler跟踪单据操作时产生的SQL语句》
  20. Subsequence Count 2017ccpc网络赛 1006 dp+线段树维护矩阵

热门文章

  1. Python电影数据分析
  2. Redis学习笔记1-java 使用Redis(jedis)
  3. POJ 1062 昂贵的聘礼 最短路+超级源点
  4. Spring-Cloud-Alibaba Nacos 启动失败,窗口一闪而过
  5. Mysql性能优化:为什么你的count(*)这么慢?
  6. 下拉框select-&gt;option中如何把参数传到视图函数中去
  7. sql 数据库操作语句 不带select
  8. ovirt 重新安装主机失败
  9. linux 之虚拟机的安装与介绍
  10. Linux基础:Day06