1. 程式人生 > >[LeetCode][初級演算法][排序] 合併兩個有序陣列

[LeetCode][初級演算法][排序] 合併兩個有序陣列

乍一看像是歸併排序,但是從題目來看明顯是可以使用原地演算法的。

使用額外陣列的方法很簡單:

void merge(int* nums1, int m, int* nums2, int n) {
    int * temp = malloc(sizeof(int)*(m+n));
    int i=0,j = 0;
    while(i<m&&j<n){    
        temp[i+j] = nums1[i]<nums2[j]?nums1[i++]:nums2[j++];                
    }

    while(i<m){
        temp[i+j] = nums1[i++];
    }
    
    while(j<n){
        temp[i+j] = nums2[j++];
    }
    
    for(i=0;i<m+n;i++){
        nums1[i] = temp[i];
    }
}

簡單的兩路歸併。

但是需要注意到題目的條件,nums1的容量是大於等於m+n的,也就是說可以直接把結果放進m+n。

但如何在不影響nums1原本元素的情況下進行排序?nums1的前m個空間存著待排序元素,但後n個空間一定是空的。

那麼如果從尾部開始填入排序的結果就不會有問題了,因為就算把nums2的n個元素全部塞進nums1尾部,

也不會擠到nums1自己的元素。

採用這樣的方法相當於反向歸併,從隊尾開始,取較大的元素。

void merge(int* nums1, int m, int* nums2, int n) {
        int idx = m + n - 1;
    int i = m - 1;
    int j = n - 1;
    while(i >= 0 && j >= 0) {
        int a = nums1[i], b = nums2[j];
        if(a > b) {
            i--;
            nums1[idx--] = a;
        } else {
            j--;
            nums1[idx--] = b;
        }
    }
    while(i >= 0) {
        nums1[idx--] = nums1[i--];
    }
    while(j >= 0) {
        nums1[idx--] = nums2[j--];
    }
}