【歸併排序】-求逆序數算法

1.歸併排序

  • 歸併排序是分治法的一種典型應用,應用遞歸思想,自頂向下思考:先假定MergeSort()可以將一個亂序數組排好序,因此可以開始(將一個數組平均分成兩部分),再(分別調用MergeSort()使前後兩部分有序),最後使用Merge()將兩個有序數組合併爲一個有序數組。
  • Merge()方法實現簡單,只需管理兩個指針,分別指向待合併的兩個數組,開闢輔助數組保存中間結果,O(n)時間複雜度即可完成

2.逆序數

  • 逆序數的定義:如果i < jA[i] > A[j].則A[i]A[j]即爲逆序數對.逆序數對的個數就叫逆序數
  • 求逆序數可以通過管理兩個指針,兩次掃描數組,蠻力法求出,顯然時間複雜度是Θ(n^2).
  • 利用歸併排序法,稍做改進即可.在Merge()中,合併兩個已經有序的數組A,B.因爲A.B有序,所以,A,B各自的逆序數是0,所以AB的逆序數等於A,B之間的逆序數.
  • 舉個例子: A=1,4,6,7,9B=2,3,5,10,13,21.在Merge中發現當前i號元素4比2大,那麼4的逆序數需要+1,又因6,7,9都排在4後面,那麼6,7,9的逆序數也應該+1,所以總體的逆序數應該加上last-i+1.
    在這裏插入圖片描述
import java.util.ArrayList;
import java.util.Arrays;
public class Solution {
    public int InversePairs(int[] array) {
        int len = array.length;
        int[] c = new int[len];
        count = 0;
        MergeSort(array, 0, len - 1, c);
        return count;
    }

    public static int MOD = 1000000007;
    public static int count = 0;//新增

    public static void Merge(int[] array, int left, int mid, int right, int[] c) {
        int i = left;
        int j = mid + 1;
        int k = left;
        while (i <= mid && j <= right) {
            if (array[i] <= array[j])
                c[k++] = array[i++];
            else {
                c[k++] = array[j++];
                //count += mid - i + 1;//新增
                count = (count + mid - i + 1) % MOD;
            }
        }
        while (i <= mid)
            c[k++] = array[i++];
        while (j <= right)
            c[k++] = array[j++];
        //C數組已經有序,將數組複製回原數組
        for (int in = left; in <= right; in++) {
            array[in] = c[in];
        }
    }

    public static void MergeSort(int[] array, int left, int right, int[] c) {
        if (left < right) {
            int mid = (left + right) / 2;
            MergeSort(array, left, mid, c);   //將第一個數組排好
            MergeSort(array, mid + 1, right, c);    //將第二個數組排好
            Merge(array, left, mid, right, c);     //合併兩個有序數組
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章