LeetCode算法 -- 合併兩個有序數組(第9題)

一、題目介紹

在這裏插入圖片描述

二、數組拷貝解法

2.1 解法介紹

因爲數組 1 的總長度是大於等於 m+n 的,所以把數組 2 的元素都拷貝到數組1中。數組 1 中的元素有 m 個,所以數組 2 中的第一個元素拷貝到數組 1 中對應的下標就是m,第二個元素拷貝過來對應的下標是 m+1,一直到 m+n-1 拷貝完後,將數組 1 整體排序一遍就搞定了,這裏用了 Arrays.sort()
內部爲快速排序,時間複雜度爲 O((n+m) * log(n+m)),空間複雜度 O(1)。這種方法沒有利用兩個數組本身已經有序這一點。

2.2 java 代碼

    /**
     * 數組拷貝後進行排序
     */
    public static void merge1(int[] nums1, int m, int[] nums2, int n) {
        for (int i = m, j = 0; i < n + m; i++, j++) {
            nums1[i] = nums2[j];
        }
        Arrays.sort(nums1);
    }

三、雙指針解法(從前到後)

3.1 解法介紹

這裏用兩個指針分別指向數組1的開頭,和數組2的開頭。跟鏈表合併不同,如果往數組中插入一個元素,爲了保證整體的順序性,需要挪動前後的元素,所以我們需要再新建一個數組。之後比較兩個數組中的元素 nums1[i] 和 nums2[j],將其放到新數組中。

這種兩兩合併的好處是可以免掉排序了,比較完之後再放到新數組中,元素都是有序的了。但題目要求是在數組1的基礎上進行修改,而不是返回一個新數組,所以我們還得把排序好的新數組內容,再重新賦給數組1。

該解法需要開闢額外的存儲空間,時間複雜度爲 O(n + m),空間複雜度爲 O(n + m)。

在這裏插入圖片描述

3.2 java 代碼


	public static void merge2(int[] nums1, int m, int[] nums2, int n) {
        int i = 0;
        int j = 0;
        int k = 0;
        int[] arr = new int[n + m];

        while (j < m || k < n) {
            //注意兩個邊界條件:j==m,以及 k==n,表示一個數組已經拷貝完了
            if (j == m) {
                arr[i++] = nums2[k++];
            } else if (k == n) {
                arr[i++] = nums1[j++];
            } else if (nums1[j] <= nums2[k]) {
                arr[i++] = nums1[j++];
            } else {
                arr[i++] = nums2[k++];
            }
        }

        System.out.println(Arrays.toString(arr));

        //還需要將新數組中的元素再拷貝回去
        for (i = 0; i < arr.length; i++) {
            nums1[i] = arr[i];
        }
    }

四、雙指針(從後往前)

4.1 解法介紹

解法二中將兩個數組合併到一個新數組中,是從兩個數組的開頭開始一一比較。這是符合直覺的,但仔細想想,數組 1 和數組 2 都是有序的,所以從前往後看是有序,從後往前看也是有序。另外題目中也說明了,數組 1 的空間是足夠的,它可以完全容納下數組 1 的 m 個元素和數組 2 的 n 個元素。
這兩個條件拼在一起,我們就有了新的比較方式,即:反着比較。

反着比較 nums1[m-1] 和 nums2[n-1],這回我們不用再新建一個數組了,數組 1 後面都是空着的,也有足夠空間可以容納下數組 2 中的所有元素。我們將兩個數組中最大的數放到數組 1 的最後一位(下標 n+m-1 處),將倒數第二大的數放到數組1的倒數第二位(下標 n+m-2 處)。依次類推直到兩個數組的元素全部比較完。

最後數組 1 就是有序的,這種比較方式不需要再佔用額外的空間。時間複雜度爲 O(n + m),空間複雜度爲 O(1)。

4.2 java 代碼

    /**
     * 雙指針(從後向前)
     */
    public static void merge3(int[] nums1, int m, int[] nums2, int n) {
        int i = m - 1;
        int j = n - 1;
        int k = m + n - 1;
        while (i >= 0 || j >= 0) {
            //注意兩個邊界條件,i<0以及j<0,這表示一個數組已經拷貝完了
            if (i < 0) {
                nums1[k--] = nums2[j--];
            } else if (j < 0) {
                nums1[k--] = nums1[i--];
            }
            //反向比較時,拷貝的是較大的那個元素
            else if (nums1[i] <= nums2[j]) {
                nums1[k--] = nums2[j--];
            } else {
                nums1[k--] = nums1[i--];
            }
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章