【每日算法Day 96】騰訊面試題:合併兩個有序數組

昨天騰訊一面上來就給我整的這道 easy 難度的題,然後我太緊張了還想了一會兒,差點炸裂。

題目鏈接

LeetCode 88. 合併兩個有序數組[1]

題目描述

給你兩個有序整數數組 nums1nums2,請你將 nums2 合併到 nums1 中,使 nums1 成爲一個有序數組。

說明:

  • 初始化 nums1nums2 的元素數量分別爲 mn
  • 你可以假設 nums1 有足夠的空間(空間大小大於或等於 m + n)來保存 nums2 中的元素。

示例1

        輸入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6],       n = 3
輸出:
[1,2,2,3,5,6]
解釋:
      

題解

看到這道題,腦海裏應該第一時間想到的是歸併排序,但是歸併排序需要一個額外的數組用來保存排序後的數組,這裏不允許使用額外空間。

那麼我們還是用歸併排序的思路來做,試一下兩個指針 i = 0j = 0 ,初始的時候分別指着 nums1[0]nums2[0] 。然後比較 nums1[i]nums2[j] 大小,如果 nums1[i] 更小,那麼就放在原位不動它,然後 i += 1。如果 nums2[j] 更小,那麼就交換 nums1[i]nums2[j] ,然後還是 i += 1。這麼看貌似可行哦?但是最終一定會先遍歷完 nums1,然後 j 還是停留在 0 ,然後你會發現 nums2 中的數字還是亂序的,根本沒法處理。

那麼怎麼利用上 nums1 後面多出的那麼多空位呢?我們可以換個思路,從最大的開始遍歷。兩個指針初始的時候 i = m-1j = n-1 ,然後將較大值填充到 nums1 的最後面。最後如果 nums2 中還有剩餘,就依次填充到 nums1 最前面就行了。

這樣爲什麼就可以了呢?因爲如果從小到大遍歷的話,元素會覆蓋掉 nums1 中還沒遍歷的元素。但是從大到小是填充到尾部,就不會產生覆蓋。就算極限情況下 nums2 中元素全部大於 nums1 中元素,也不會覆蓋到 nums1 的最後一個元素。

面試官最後還會問你有啥優化,我當時圖省事,最後還把 nums1 中剩下元素填充到 nums1 最前面了,其實完全沒有必要,本來就是有序的,等於沒有做事。

代碼

c++

        class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        int i = m-1, j = n-1, k = m+n-1;
        while (i >= 0 && j >= 0) {
            if (nums1[i] > nums2[j]) nums1[k--] = nums1[i--];
            else nums1[k--] = nums2[j--];
        }
        while (j >= 0) nums1[k--] = nums2[j--];
    }
};

      

python

        class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        i, j = m-1, n-1
        while i >= 0 and j >= 0:
            if nums1[i] > nums2[j]:
                nums1[i+j+1] = nums1[i]
                i -= 1
            else:
                nums1[i+j+1] = nums2[j]
                j -= 1
        while j >= 0:
            nums1[j] = nums2[j]
            j -= 1

      

參考資料

[1]

LeetCode 88. 合併兩個有序數組: leetcode-cn.com/problem

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