1. 程式人生 > >資料結構演算法題/合併兩個有序陣列

資料結構演算法題/合併兩個有序陣列

給定兩個有序整數陣列 nums1 和 nums2,將 nums2 合併到 nums1 中,使得 num1 成為一個有序陣列。

說明:

初始化 nums1 和 nums2 的元素數量分別為 m 和 n。
你可以假設 nums1 有足夠的空間(空間大小大於或等於 m + n)來儲存 nums2 中的元素。
示例:

輸入:
nums1 = [1,2,3,0,0,0], m = 3(後面的三個0是額外的元素)
nums2 = [2,5,6],       n = 3

輸出: 

[1,2,2,3,5,6]

(1)忽略nums1後面多餘的元素,額外使用一個輔助陣列C

時間O(m+n),空間複雜度O(m+n) 

假設兩個有序陣列都是升序,新建陣列C,長度為陣列A和陣列B的長度之和,從索引0出依次設定陣列C對於下標的值

/**
 * 合併兩個有序陣列
 * 假設兩個有序陣列都是升序,新建陣列C,長度為陣列A和陣列B的長度之和,從索引0出依次設定陣列C對於下標的值
 */
public class SortedArrayCombine {
    public static void main(String[] args) {
        int[] a = {1, 3, 5, 7, 9, 11, 13};
        int[] b = {2, 4, 6, 8, 10, 12};
        int[] c = new int[a.length + b.length];

        int i = 0;
        int j = 0;
        for (int k = 0; k < c.length; k++) {
            if (i < a.length && j < b.length) {//a和b都沒走完
                if (a[i] <= b[j]) {
                    c[k] = a[i];
                    i++;
                } else {
                    c[k] = b[j];
                    j++;
                }
            } else if (i < a.length) {//或者else if(i < a.length && j >= b.length) 也就是b走完了
                c[k] = a[i];
                i++;
            } else if (j < b.length) {//或者else if(i >= a.length && j < b.length) 也就是a走完了
                c[k] = b[j];
                j++;
            } else {
                throw new RuntimeException("不可能情況");
            }
        }

        for (int k = 0; k < c.length; k++) {
            System.out.print(String.valueOf(c[k]) + " ");
        }
    }
}

(2)無輔助陣列,時間複雜度為O(n+m),而空間複雜度為O(1)

思路

剛開始接觸題就想到暴力解法,先將B加入到A的後面,然後對組合後的陣列進行排序,假設A和B的長度分別是M,N,那麼用快排平均也需要nlog(n)的時間複雜度;顯然不是一種很好的做法;

第二種想法是再利用一個數組,然後A和B分別比較較小的元素加入到新的陣列中,這樣時間複雜度是O(M+N),但是空間複雜度又增加了O(M);這種也不是好辦法;

第三種想法是在A的左邊開始和b比較然後將B插入A中,這種演算法移動元素的次數較多;移動一次的時間複雜度O(M),這種演算法的時間複雜度是O(M*N);顯然也不是好辦法;

第四種,也是比較推薦的演算法是,先算出A和B的總長度,由於陣列中後面的元素是空的,可以從後往前複製,時間複雜度是O(M+N);空間複雜度是O(1);這種想法是比較好的,基於第四種演算法的思想做了如下的Java實現
 

從大的開始比較和”入隊“。 
比如1 3 5和2 4合併的話,從尾部比較: 
5比4大,5放到最後邊; 
3比4小,4放到5的前面一格; 
3比2大,3放到4的前面一格; 
1比2小,2放到3的前面一格; 
1,沒人來比較,1放到2的前面一格。 
END

public class SortedArrayCombine2 {
    public static void main(String args[]) throws Exception {
        int[] source1 = new int[50];
        source1[0] = 1;
        source1[1] = 2;
        source1[2] = 5;
        source1[3] = 9;
        source1[4] = 13;
        int[] source2 = new int[] { 1, 3, 4, 8, 10 };
        mergeArray(source1, source2, 5);
//        mergeArray(source1, source2, 100);
//        mergeArray(source1, null, 5);
//        mergeArray(null, source2, 5);
//        mergeArray(source1, source2, 4);
    }

    /**
     * @param source1
     * @param source2
     * m表示陣列1已有資料長度這裡是5
     * n表示陣列2已有資料長度
     * length=m+n表示合併之後陣列中的資料個數
     * @return
     */
    public static int[] mergeArray(int[] source1, int[] source2, int m) {
        /** 先進行判空,如果都非空,長度為0可認為是正確的 */
        if (source1 == null || source2 == null) {
            System.out.println("there is a null arr");
            return null;
        }
        /** source的長度和已有M不匹配 */
        if (m > source1.length) {
            System.out.println("the length unmatch with m");
            return null;
        }

        int n = source2.length;
        int length = m + n;//兩個數組合並之後的新陣列中元素的數量

        if (source1.length < length) {
            System.out.println("陣列1的空間不夠容納陣列1和2中的元素");
            return null;
        }

        int i = length - 1;
        // M+N次運算,上面都是一些特殊資料處理
        for (; i >= 0 && m > 0 && n > 0; i--) {
            //下面是把source1和source2中相對最大的那個放到合併的陣列的後面(i = length - 1)
            if (source1[m - 1] > source2[n - 1]) {
                source1[i] = source1[m - 1];
                m--;
            } else {
                source1[i] = source2[n - 1];
                n--;
            }
        }
        // 比較完剩餘的元素能順利插入
        while (m > 0) {
            source1[i--] = source1[m--];
        }
        while (n > 0) {
            source1[i--] = source2[n--];
        }
        for (int count = 0; count < length; count++) {
            System.out.print(String.valueOf(source1[count]) + " ");
        }
        return source1;
    }
}