1. 程式人生 > 其它 >明明兩種方式都可以合併陣列,為什麼老師就是讓我用雙指標實現

明明兩種方式都可以合併陣列,為什麼老師就是讓我用雙指標實現

一、題目描述

合併兩個有序陣列

給你兩個有序整數陣列 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陣列準備的預留空間。
  • 根據題意我們也可以得出本題想讓我們不接觸第三方變數的情況下實現兩個陣列的合併。但是剛才說的整合後在合併這個就沒有用到第三方
  • 自始至終我們沒有引入第三方變數。這種的確是最快最簡單的實現方式

雙指標

  • 雙指標的意思就是定義兩個指標(變數索引)指向兩個陣列,將兩個陣列看做是兩個佇列每次將兩個佇列中較小值去除塞到第三個陣列中。最終第三個陣列就是我們排序好的合併陣列
  • 之前也分析了本題題意是不想讓我們藉助第三方變數來實現的。那麼如果不借助第三個陣列我們是否可以利用雙指標來實現合併呢?
  • 答案是可以的。因為題目中指出了num1就是合併後陣列的長度。很明顯就是讓我們將num1作為合併後的陣列輸出的。
  • 我們可以逆向從num1陣列開始將集合中最大數填入num1尾部,然後將其次大的填入倒數第二個位置,一次類推最後就會全部填入num1陣列中。
  • 最極端的情況是num2正好全部填充在num1後半部分,那麼這樣我們num1前半部分元素正好不需要移動。
  • 只要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中。

四、總結

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

點贊+評論哦