歸併排序練習題(Java)

1、算法原理:

首先歸併排序的基本是將兩個數組合並,將兩個有序的數組合併爲一個有序的數組,需要一個額外的輔助數組,例如a、b數組,合併爲c

  • c[0] 是 a[0] 和 b[0] 中較小的數,假設是a[0],然後a數組的指針加1 變爲a[1]
  • c[1] 是 a[1] 和 b[0] 中較小的數,如此類推

這樣進行一次合併時間複雜度是O(n)

歸併排序的思想是,將整個數組2等分地無限拆分爲每組只有1個數的小單元,一共要拆分logn次
然後小的1個數的單元進行有序的合併,形成有序的每組有2個數的小單元,然後再進行合併形成有4個數的單元,一共進行logn次,而每次合併都是一次合併的時間複雜度O(n)。

所以整體的時間複雜度是 logn * O(n) = O(nlogn)
空間複雜度是利用的額外數組 O(n)

2、算法實現

private void mergeSort(int[] nums, int begin, int end, int[] auxiliaryArray){
        if(begin < end){
            int mid = (begin + end) / 2;
            mergeSort(nums, begin, mid, auxiliaryArray);
            mergeSort(nums, mid+1, end, auxiliaryArray);
            mergeArray(nums, begin, mid, end, auxiliaryArray);
        }
    }

private void mergeArray(int[] nums, int begin, int mid, int end, int[] auxiliaryArray){
        int leftPointer = begin, rightPointer = mid + 1;
        int auxIndex = 0;

        while(leftPointer <= mid && rightPointer <= end){
            if(nums[leftPointer] <= nums[rightPointer]){
                auxiliaryArray[auxIndex++] = nums[leftPointer++];
            }else{
                auxiliaryArray[auxIndex++] = nums[rightPointer++];
            }
        }

        while(leftPointer <= mid){
            auxiliaryArray[auxIndex++] = nums[leftPointer++];
        }

        while(rightPointer <= end){
            auxiliaryArray[auxIndex++] = nums[rightPointer++];
        }

        for(int i = 0; i < auxIndex; i++){
            nums[begin + i] = auxiliaryArray[i];
        }
    }

3、算法習題

lintcode 532. 逆序對

解題思路:
利用歸併排序,歸併排序其實就是一個消除逆序對的過程,從最小的單元開始消除,2個一組消除,4個一組消除,可以在O(nlogn)的時間複雜度中,找出所有的逆序對。

public class Solution {
    /**
     * @param A: an array
     * @return: total of reverse pairs
     */
    public long reversePairs(int[] A) {
        // write your code here
        int[] auxiliaryArray = new int[A.length];
        int sum = 0;
        sum = mergeSort(A, 0, A.length-1, auxiliaryArray);
        return sum;
    }
    
    private int mergeSort(int[] nums, int begin, int end, int[] auxiliaryArray){
        int sum = 0;
        if(begin < end){
            int mid = (begin + end) / 2;
            sum += mergeSort(nums, begin, mid, auxiliaryArray);
            sum += mergeSort(nums, mid+1, end, auxiliaryArray);
            sum += mergeArrayAndCountReversePairs(nums, begin, mid, end, auxiliaryArray);
        }
        return sum;
    }
    
    private int mergeArrayAndCountReversePairs(int[] nums, int begin, int mid, int end, int[] auxiliaryArray){
        int leftPointer = begin, rightPointer = mid + 1;
        int auxIndex = 0;
        int sum = 0;

        while(leftPointer <= mid && rightPointer <= end){
            if(nums[leftPointer] <= nums[rightPointer]){
                auxiliaryArray[auxIndex++] = nums[leftPointer++];
            }else{
                auxiliaryArray[auxIndex++] = nums[rightPointer++];
                sum += mid + 1 - leftPointer;
            }
        }

        while(leftPointer <= mid){
            auxiliaryArray[auxIndex++] = nums[leftPointer++];
        }

        while(rightPointer <= end){
            auxiliaryArray[auxIndex++] = nums[rightPointer++];
        }

        for(int i = 0; i < auxIndex; i++){
            nums[begin + i] = auxiliaryArray[i];
        }

        return sum;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章