讓我們一起啃演算法----合併兩個有序陣列

三斤和他的喵發表於2020-04-25

合併兩個有序陣列(Merge-Sorted-Array)

題幹:

給你兩個有序整數陣列 nums1 和 nums2,請你將 nums2 合併到 nums1 中,使 nums1 成為一個有序陣列。
說明:
初始化 nums1 和 nums2 的元素數量分別為 m 和 n 。
你可以假設 nums1 有足夠的空間(空間大小大於或等於 m + n)來儲存 nums2 中的元素。
示例:
  輸入:
  nums1 = [1,2,3,0,0,0], m = 3
  nums2 = [2,5,6], n = 3
  輸出: [1,2,2,3,5,6]
來源:力扣(LeetCode)

這是一題關於陣列的題目。目前為止講解陣列、字串相關的題目都會引入一個解題思路: 雙指標思路。其實就是想讓小夥伴們培養一個習慣:面對陣列、字串型別的題目先用 雙指標思路 來搗騰搗騰。

當然這題也是引用這個思路來解題,只不過這時候的 雙指標 不在指向一個陣列,而是分別指向陣列 num1num2

解題思路

簡單粗暴的方式就是將 num1num2 直接合並,再重新排序,當然不建議這麼做啦。

我們仔細審一下題:題目告訴我們 num1num2 是有序的,並且是從小到大排序的。那我們是不是可以從左到右依次比較 num1num2 中的元素值,並將 較小的值minV 逐一儲存到一個新的陣列 num3 中。

但是題目有一個限制:需要將 num2 直接合併到 num1 中。這時候我們發現用從左到右的方式遍歷,並將 minV 插入到 num1 中勢必會產生挪動 num1 元素的操作,例如:需要在 num1 索引為 2 的位置插入 minV,那麼需要將原本 索引為 2 的元素以及之後的元素都向後挪一位,空出索引為 2 的位置。成本有點大,並且也不好實現。

那麼如何解決上面的問題呢?其實換成從右向左遍歷就行啦。我們知道 num1 現在的長度為 m,當前最大索引記為 inum2 的長度為 n,當前最大索引記為 j,合併之後 num1 的長度應該是 m + n,最大索引記為 max。我們比較 num1[i]num2[j] 的大小,如果 num1[i] 大於 num2[j] ,那麼 num1[max] = num1[i],max 向左移動一位,i 向左移動一位,反之 num1[max] = num2[j],max 向左移動一位,j 向左移動一位。重複上面的操作,具體流程以及一些邊界問題,檢視下面的流程圖:

程式碼實現

func merge(nums1 []int, m int, nums2 []int, n int) {

    // max 指向 nums1 與 nums2 合併之後的最後一個元素
    max := m + n - 1

    // 指向 num1 最後一個元素
    i := m - 1

    // 指向 num2 最後一個元素
    j := n -1


    for i >= 0 && j >= 0 {

        // 從右向左比較值的大小
        if nums1[i] > nums2[j] {
            nums1[max] = nums1[i]

            // i 向左移動
            i--
        } else {
            nums1[max] = nums2[j]

            // j 向左移動
            j--
        }

        // max 向左移動
        max --




    }

    // 如果 i 越界了,將 nums2 剩餘的元素賦值到 num1 的 [0,m] 之間
    for j >= 0 {
        nums1[max] = nums2[j]
        max--
        j--
    }

    // 如果 j 越界了,其實下面這個迴圈可以省略。
    for i >= 0 {
        nums1[max] = nums1[i]
        max--
        i--
    }
}

總結

每天進步一點點,加油!
演算法教程專案,每天更新一題,點個 star 支援一下呀
https://github.com/wx-satellite/learning-a…

本作品採用《CC 協議》,轉載必須註明作者和本文連結

三斤

相關文章