Insertion Sort is a simple sorting technique which was covered in previous challenges. Sometimes, arrays may be too large for us to wait around for insertion sort to finish. Is there some other way we can calculate the number of times Insertion Sort shifts each elements when sorting an array?

If ki is the number of elements over which ith element of the array has to shift then total number of shift will be k1 + k2 + ... + kN.

Input: 
The first line contains the number of test cases T. T test cases follow. The first line for each case contains N, the number of elements to be sorted. The next line contains N integers a[1],a[2]...,a[N].

Output: 
Output T lines, containing the required answer for each test case.

Constraints: 
1 <= T <= 5 
1 <= N <= 100000 
1 <= a[i] <= 1000000


好恶心的题,从早上做到现在才过,整个人昏昏沉沉的,还没从昨天20多个小时车程中恢复过来T_T

ok,来说说这道题,是要求insertion sort时数组中元素移动的次数。最naive的方法当然是直接进行一边insertion sort,输出移动次数了,这个复杂度是O(N2),会超时。

其实,Insertion Sort中元素移动的次数和这个序列中逆序数的和是相等的。因为,在把元素a[i]插入数组的过程中,已经排好序的部分数组中比它大的元素都要后移。

所以我们的问题就简化为怎样快速的求出一个序列的逆序数。网上的方法很多:Binary Search Tree(当树为单支二叉树的时候算法复杂度退化到O(N2),红黑树,归并排序等等。

这里采用归并排序的方法:在归并排序的归并这一步时候,由两个数组ar1和ar2,它们分别是原数组的前半部分和后半部分。每次取ar1和ar2数组头部最小的元素插入到排好序的数组中,当这个最小元素是从ar2中取出的时候,ar1中当前游标之后的元素都比这个最小元素大,而且在原数组中位于这个元素前面,所以此时一共输出m-point1对逆序数(m是ar1的长度,point1是当前ar1的游标)。这样我们就可以在归并排序的过程中统计出逆序数对了。

举个例子:

如上图所示,左边的图显示了整个归并过程中统计逆序数的过程。橙色的数字表示在每次归并中输出的逆序数对,最后把数出的所有逆序数对相加即可。

右边的图显示了具体合并(1,7)和(2,9)的过程,第二步要合并2的时候,发现在第一个数组中有个7比2大,那么此时(7,2)就是序列的一对逆序数。

最后一个细节是,当ar1和ar2的头部元素相等的时候,那么直接取ar1头部元素放入归并后的数组就可以了。

代码如下:

 import java.util.*;

 public class Solution {
private static long answer = 0; private static int[] Merge(int[] ar1,int[] ar2){
int m = ar1.length;
int n = ar2.length; int point1 = 0;
int point2 = 0;
int index_result = 0;
int[] result = new int[m+n];
while(point1 < m && point2 < n){
if(ar1[point1] < ar2[point2]){
result[index_result] = ar1[point1];
point1++;
index_result++;
}
else if(ar1[point1] > ar2[point2]){
answer += m - point1;
result[index_result] = ar2[point2];
index_result++;
point2++;
}
else{
result[index_result] = ar1[point1];
index_result++;
point1++;
}
}
while(point1 < m){
result[index_result] = ar1[point1];
index_result++;
point1++;
}
while(point2 < n){
answer += m - point1;
result[index_result] = ar2[point2];
index_result++;
point2++;
}
return result;
}
private static int[] mergeSort(int[] ar){
int n = ar.length;
if(n <= 1)
return ar;
int mid = n/2;
int[] ar1 = new int[mid];
int[] ar2 = new int[n-mid];
System.arraycopy(ar, 0, ar1, 0, mid);
System.arraycopy(ar, mid, ar2, 0, n-mid);
int[] sorted_ar1 = mergeSort(ar1);
int[] sorted_ar2 = mergeSort(ar2);
int[] result = Merge(sorted_ar1, sorted_ar2);
return result;
}
public static void main(String[] args) { Scanner in = new Scanner(System.in);
int T = in.nextInt();
for(int k = 0;k < T;k++){
answer = 0;
int n = in.nextInt();
int[] ar = new int[n];
for(int i = 0;i < n;i++)
ar[i] = in.nextInt();
mergeSort(ar);
System.out.println(answer);
}
}
}

【HackerRank】Insertion Sort Advanced Analysis(归并排序求数列逆序数对)的更多相关文章

  1. 线段树解Insertion Sort Advanced Analysis

    题目出处 题意描述: 这个题目提问的是,在插入排序的序列给定的情况下,求最少需要移动的次数. 序列的长度n <=10^5 序列中的元素a[i] <=10^6 一组数据中case数t < ...

  2. 【归并排序】【逆序数】HDU 5775 Bubble Sort

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5775 题目大意: 冒泡排序的规则如下,一开始给定1~n的一个排列,求每个数字在排序过程中出现的最远端 ...

  3. HDU 1394 Minimum Inversion Number(线段树求最小逆序数对)

    HDU 1394 Minimum Inversion Number(线段树求最小逆序数对) ACM 题目地址:HDU 1394 Minimum Inversion Number 题意:  给一个序列由 ...

  4. Reduce inversion count 求最小逆序数

    本问题出自:微软2014实习生及秋令营技术类职位在线测试 (Microsoft Online Test for Core Technical Positions) Description Find a ...

  5. HDU2838 Cow Sorting 树状数组 区间求和加逆序数的应用

    这题目意思非常easy,就是给你一个数组,然后让你又一次排好序,排序有要求的,每次仅仅能交换两个元素的位置,交换须要一个代价 就是两个元素之和,问你把数组重小到大排好最少须要多少代价 可能一開始想不到 ...

  6. hdu-1394(线段树求最小逆序数)

    http://acm.hdu.edu.cn/showproblem.php?pid=1394 题意: 给定一个n,然后又n个数字,首先,这些数字的大小是从0开始到n-1,比如样例n=10,则这十个数就 ...

  7. 归并排序(包含逆序数对的个数51Nod1019)

    归并排序是效率很好的排序方式,和快排效率一样高,但在稳定性上优于快排,下面我们来介绍归并排序. 归并排序运用递归将序列不断二分(其原理就是分治),就像一棵树不断向下分支,最后分到只剩一个元素,这样这个 ...

  8. hdu1394Minimum Inversion Number(线段树,求最小逆序数)

    Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java ...

  9. poj 1804 (nyoj 117)Brainman : 归并排序求逆序数

    点击打开链接 Brainman Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 7810   Accepted: 4261 D ...

随机推荐

  1. 解决xshell6评估过期,需采购问题

    2018年12月20日补充 绿色免安装版: https://www.lanzous.com/i2njdre 密码:9b7t 2018年7月18日补充 感谢s***5大佬提供注册包,有需要的小伙伴,请留 ...

  2. 第二百零二节,jQuery EasyUI,Layout(布局)组件

    jQuery EasyUI,Layout(布局)组件 学习要点: 1.加载方式 2.布局属性 3.区域面板属性 4.方法列表 本节课重点了解 EasyUI 中 Layout(布局)组件的使用方法,这个 ...

  3. php 打印debug日志

    A lesser known trick is that mod_php maps stderr to the Apache log. And, there is a stream for that, ...

  4. Redis 安装成windows服务- 一主二从三哨兵,sentinel安装为Windows服务

    这里只做记录说明 Redis的主从配置网上很多文章,百度一大堆,安装流程应该都可以配置通.我使用的这篇文章 https://blog.csdn.net/u010648555/article/detai ...

  5. 红外图像盲元补偿matlab实现源码与效果验证

    在国内红外公司绝大多数一直以来国外进口的成像芯片,能够进行红外芯片自助开发的电学应该只有大立光电和广微积电光学方法只有上海巨哥和一直未能产 品化的昆山光微电子.由于政治和历史原因,欧美对中国大陆还是实 ...

  6. 强大的find命令

    find命令确实很强大,自己懒得计,转载一篇: 原文出处:http://roclinux.cn/?p=18 1. 想查看当前文件夹及子文件夹里有没有文件名为“abc”的文件 # find . -nam ...

  7. matlab7.0安装 win7系统详细使用方法附软件下载

    MATLAB 7.0下载地址: 百度网盘下载地址:http://pan.baidu.com/share/link?shareid=414204&uk=2769186556 迅雷快传下载地址:h ...

  8. python学习【第十一篇】网络编程

    一.socket的简介 socket(简称:套接字)进程间通信的一种方式,它与其他进程间通信的一个主要不同是:能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通 ...

  9. IIS配置(持续更新中...)

    本文暂时适用于IIS7.5. IIS配置文件路径:"C:\Windows\System32\inetsrv\config\applicationHost.config" 1.sta ...

  10. .net framework 4.5 在Visual studio 2015中丢失

    解决办法:从另一台C:\Program Files(x86)\Reference Assemblies\Microsoft\.NetFramework 成功的环境中copy .net4.5 文件夹到错 ...