明明兩種方式都可以合併數組,爲什麼老師就是讓我用雙指針實現

一、題目描述

合併兩個有序數組

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

初始化 nums1 和 nums2 的元素數量分別爲 m 和 n 。你可以假設 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]

示例 2:

輸入:nums1 = [1], m = 1, nums2 = [], n = 0
輸出:[1]

二、思路分析

常規解析

  • 相信大家首先想到的就是兩個數組融合然後對整體數組進行排序,不得不說這種方法是最快的因爲我們有線程的api直接操作。撩撩幾行代碼就可以解決問題
  • 本題中說明了這兩個數組是有序的 , num1前半部分是有序的,後半部分是爲了存儲num2數組準備的預留空間。
  • 根據題意我們也可以得出本題想讓我們不接觸第三方變量的情況下實現兩個數組的合併。但是剛纔說的整合後在合併這個就沒有用到第三方

image-20210525193732712

  • 自始至終我們沒有引入第三方變量。這種的確是最快最簡單的實現方式

雙指針

  • 雙指針的意思就是定義兩個指針(變量索引)指向兩個數組,將兩個數組看做是兩個隊列每次將兩個隊列中較小值去除塞到第三個數組中。最終第三個數組就是我們排序好的合併數組

image-20210525194330292

  • 之前也分析了本題題意是不想讓我們藉助第三方變量來實現的。那麼如果不借助第三個數組我們是否可以利用雙指針來實現合併呢?
  • 答案是可以的。因爲題目中指出了num1就是合併後數組的長度。很明顯就是讓我們將num1作爲合併後的數組輸出的。
  • 我們可以逆向從num1數組開始將集合中最大數填入num1尾部,然後將其次大的填入倒數第二個位置,一次類推最後就會全部填入num1數組中。

image-20210526141857309

  • 最極端的情況是num2正好全部填充在num1後半部分,那麼這樣我們num1前半部分元素正好不需要移動。

image-20210526142031061

  • 只要num2沒有全部填入後半部分,那麼num1前半部分肯定有最大的值發生移動。那麼發生移動的地方肯定優先是前半部分的末尾,那麼num2就機會參與。
  • 所以不管什麼情況,都不會發生num1數組中元素被佔用的情況

三、AC 代碼

public void merge(int[] nums1, int m, int[] nums2, int n) {
    int p1 = m - 1;
    int p2 = n - 1;
    for (int i = nums1.length - 1; i >= 0; i--) {
        int num1=Integer.MIN_VALUE, num2 = Integer.MIN_VALUE;
        if (p1 >= 0) {
            num1 = nums1[p1];
        }
        if (p2 >= 0) {
            num2 = nums2[p2];
        }
        if (num1 > num2) {
            p1--;
            nums1[i] = num1;
        } else {
            p2--;
            nums1[i] = num2;
        }
    }
}
  • 主要思路就是針對num1開始循環填充數據,每次都通過雙指針從數組尾部獲取最大值填入num1中。

image-20210526143554833

四、總結

  • 起初肯定是全部合併,然後排序這種做法簡單直接也很粗暴。沒有考慮數組的特性即題目的意思
  • 然後就是雙指針合併,缺點是藉助第三變量。
  • 轉變下思路我們通過雙指針逆向開始填充數據,徹底解決第三變量的問題

點贊+評論哦

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