前言
大家好,今天給大家帶來一道與「數組」相關的題目,這道題同時也是字節、微軟和亞馬遜等互聯網大廠的面試題,即力扣上的第 88 題-合並兩個有序數組。
本文主要介紹「逆向雙指針」的策略來解答此題,供大家參考,希望對大家有所幫助。
合並兩個有序數組

解題思路
合並兩個「有序」數組,比較容易想到的策略主要有以下幾種:
為了方便描述,假設長度更長的數組為 nums1,長度稍微短一點的數組為 nums2,下文也是一直遵循這種描述。
❝策略一:將 nums2 中的元素全部插入到 nums1 的尾部,然后對處理之后的 nums1 進行排序。
❞
❝策略二:雙指針法,先開辟一個新數組,長度為兩個數組的長度之和,然后讓兩個指針分別指向兩個數組的頭部,比較這個兩個指針指向的數組元素的值,將數值較小的放到新數組的頭部,再將指向的數值較小的指針右移,繼續比較,直到遍歷完其中一個數組即可。
❞
「復雜度分析」
【時間復雜度】:策略一是「O((n + m)lg(n + m))」,主要是合並之后再排序的時間復雜度;策略二是「O(n + m)」,主要是遍歷兩個數組的時間復雜度。
【空間復雜度】:策略一是「O(1)」,未開辟額外的存儲空間;策略二是「O(n + m)」,額外開辟了長度為 m + n 的數組。
逆向雙指針
從前面的分析可知,策略二相對於策略一來說,時間復雜度「更優」了,但開辟了「額外」的空間。
有沒有方法能夠將策略二的空間復雜度優化呢?答案是有的,由於題目明確告知了「可以假設 nums1 的空間大小等於 m + n」,因此可以利用這個條件將策略二的空間復雜度優化。具體如下栗子分析:
「舉例」
假設 nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3,如下圖示。
按照題目要求,合並后的數組應該如下圖示:
先設置兩個指針 p 和 q,分別指向兩個數組的末尾,假設 k 為 兩數組的長度,如下圖示:
比較 p 和 q 指向數組位置的元素值
將元素值較大的存放在 nums1[k] 中,並左移 k 和 q(指向的數值較大的指針)
以此類推,其處理的完整過程如下動圖示
Show me the Code
「C」

1 void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){ 2 int p = m - 1; // p 指向 nums1[m - 1] 3 int q = n - 1; // q 指向 nums2[n - 1] 4 int k = m + n - 1; // k 指向 nums1[m + n - 1] 5 6 /* nums1、nums2 其中一個未遍歷完,不斷比較 nums1[p] 和 nums1[q],更新 nums[k] */ 7 while (p >= 0 && q >= 0) { 8 nums1[k--] = nums1[p] > nums2[q] ? nums1[p--] : nums2[q--]; 9 } 10 11 /* 若 n > m,nums1 遍歷完成,將 nums2 中尚未遍歷完的元素拷貝到 nums1 中 */ 12 while (q >= 0) { 13 nums1[k--] = nums2[q--]; 14 } 15 }
「C++」

1 void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) { 2 int p = m - 1; 3 int q = n - 1; 4 int k = nums1.size() - 1; 5 while (p >= 0 && q >= 0) { 6 nums1[k--] = nums1[p] > nums2[q] ? nums1[p--] : nums2[q--]; 7 } 8 9 while (q >= 0) { 10 nums1[k--] = nums2[q--]; 11 } 12 }
「Java」

1 void merge(int[] nums1, int m, int[] nums2, int n) { 2 int p = m - 1; 3 int q = n - 1; 4 int k = nums1.length - 1; 5 while (p >= 0 && q >= 0) { 6 nums1[k--] = nums1[p] > nums2[q] ? nums1[p--] : nums2[q--]; 7 } 8 9 while (q >= 0) { 10 nums1[k--] = nums2[q--]; 11 } 12 }
「Python3」

1 def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None: 2 p, q, k = m - 1, n - 1, len(nums1) - 1 3 while p >= 0 and q >= 0: 4 if nums1[p] > nums2[q]: 5 nums1[k] = nums1[p] 6 p -= 1 7 else: 8 nums1[k] = nums2[q] 9 q -= 1 10 k -= 1 11 12 while q >= 0: 13 nums1[k] = nums2[q] 14 q -= 1 15 k -= 1
「Golang」

1 func merge(nums1 []int, m int, nums2 []int, n int) { 2 p, q, k := m - 1, n - 1, len(nums1) - 1 3 for p >= 0 && q >= 0 { 4 if nums1[p] > nums2[q] { 5 nums1[k] = nums1[p] 6 p -= 1 7 } else { 8 nums1[k] = nums2[q] 9 q -= 1 10 } 11 k -= 1 12 } 13 14 for q >= 0 { 15 nums1[k] = nums2[q] 16 q -= 1 17 k -= 1 18 } 19 }
「復雜度分析」
時間復雜度:「O(n + m)」,需要遍歷一遍兩個數組。
空間復雜度:「O(1)」,未開辟額外的空間。