如何快速合並兩個有序數組?


前言

大家好,今天給大家帶來一道與「數組」相關的題目,這道題同時也是字節、微軟和亞馬遜等互聯網大廠的面試題,即力扣上的第 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 }
View Code

「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 }
View Code

「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 }
View Code

「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  
View Code

「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 }
View Code

「復雜度分析」

時間復雜度:「O(n + m)」,需要遍歷一遍兩個數組。

空間復雜度:「O(1)」,未開辟額外的空間。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM