標籤:style blog http color java io strong for
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頭部元素放入歸併後的數組就可以了。
代碼如下:
1 import java.util.*; 2 3 public class Solution { 4 private static long answer = 0; 5 6 private static int[] Merge(int[] ar1,int[] ar2){ 7 int m = ar1.length; 8 int n = ar2.length; 9 10 int point1 = 0;11 int point2 = 0;12 int index_result = 0;13 int[] result = new int[m+n];14 while(point1 < m && point2 < n){15 if(ar1[point1] < ar2[point2]){16 result[index_result] = ar1[point1];17 point1++;18 index_result++;19 }20 else if(ar1[point1] > ar2[point2]){21 answer += m - point1;22 result[index_result] = ar2[point2];23 index_result++;24 point2++;25 }26 else{27 result[index_result] = ar1[point1];28 index_result++;29 point1++;30 }31 }32 while(point1 < m){33 result[index_result] = ar1[point1];34 index_result++;35 point1++;36 }37 while(point2 < n){38 answer += m - point1;39 result[index_result] = ar2[point2];40 index_result++;41 point2++;42 }43 return result;44 }45 private static int[] mergeSort(int[] ar){46 int n = ar.length;47 if(n <= 1)48 return ar;49 int mid = n/2;50 int[] ar1 = new int[mid];51 int[] ar2 = new int[n-mid];52 System.arraycopy(ar, 0, ar1, 0, mid);53 System.arraycopy(ar, mid, ar2, 0, n-mid);54 int[] sorted_ar1 = mergeSort(ar1);55 int[] sorted_ar2 = mergeSort(ar2);56 int[] result = Merge(sorted_ar1, sorted_ar2);57 return result;58 }59 public static void main(String[] args) {60 61 Scanner in = new Scanner(System.in);62 int T = in.nextInt();63 for(int k = 0;k < T;k++){64 answer = 0;65 int n = in.nextInt();66 int[] ar = new int[n];67 for(int i = 0;i < n;i++)68 ar[i] = in.nextInt(); 69 mergeSort(ar);70 System.out.println(answer);71 }72 }73 }