一、題目描述
合並兩個有序數組
給你兩個有序整數數組 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中。
四、總結
- 起初肯定是全部合並,然后排序這種做法簡單直接也很粗暴。沒有考慮數組的特性即題目的意思
- 然后就是雙指針合並,缺點是借助第三變量。
- 轉變下思路我們通過雙指針逆向開始填充數據,徹底解決第三變量的問題
點贊+評論哦