# 【LeetCode刷題】【演算法學習筆記】88. Merge Sorted Array
* 學習時間:2025/2/5 (wed.)
* **題目連結(美服):** [88. Merge Sorted Array](https://leetcode.com/problems/merge-sorted-array/description/)
* **題目連結(國服):**[88. 合并两个有序数组](https://leetcode.cn/problems/merge-sorted-array/)
* **題目標籤:** ==陣列== ==雙指針== ==排序==
### A. 題目
---
You are given two integer arrays ==nums1== and ==nums2==, sorted in **non-decreasing order**, and two integers ==m== and ==n==, representing **the number of elements** in nums1 and nums2 respectively.
**Merge** nums1 and nums2 into a single array sorted in **non-decreasing order**.
The final sorted array should not be returned by the function, but instead **be stored inside the array nums1**.
To accommodate this, nums1 has a length of m + n, where the first ==m== **elements denote the elements that should be merged**, and the last n elements are set to 0 and should be ignored. **nums2 has a length of ==n==**.
Example 1:
Input: nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
Output: [1,2,2,3,5,6]
Explanation: The arrays we are merging are [1,2,3] and [2,5,6].
The result of the merge is [1,2,2,3,5,6] with the underlined elements coming from nums1.
Example 2:
Input: nums1 = [1], m = 1, nums2 = [], n = 0
Output: [1]
Explanation: The arrays we are merging are [1] and [].
The result of the merge is [1].
Example 3:
Input: nums1 = [0], m = 0, nums2 = [1], n = 1
Output: [1]
Explanation: The arrays we are merging are [] and [1].
The result of the merge is [1].
Note that because m = 0, there are no elements in nums1. The 0 is only there to ensure the merge result can fit in nums1.
### B. 題目(中文)
---
给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
**示例 1:**
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。
**示例 2:**
输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
解释:需要合并 [1] 和 [] 。
合并结果是 [1] 。
**示例 3:**
输入:nums1 = [0], m = 0, nums2 = [1], n = 1
输出:[1]
解释:需要合并的数组是 [] 和 [1] 。
合并结果是 [1] 。
注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。
### C. 參考程式碼
---
:::spoiler Solution & Thinking(力扣官方思路)
* reference: [力扣官方题解](https://leetcode.cn/problems/merge-sorted-array/solutions/666608/he-bing-liang-ge-you-xu-shu-zu-by-leetco-rrb0/)
**題解一**
* 思路:使用**雙指針**
* 程式實現:
1. 利用陣列已經排序的特性 ➡︎ 使用**雙指針**
2. 每次從兩陣列第一個元素**比較大小**,大的元素輸出欲合併陣列 **ans**
```python=
class Solution:
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
# 儲存合併後的結果的新陣列
ans = []
# 初始化指針指向兩陣列第一個元素
p1, p2 = 0, 0
# 只要 nums1 或 nums2 還沒完全處理完,就繼續執行迴圈。
while p1 < m or p2 < n:
# 特殊狀況 p1 或 p2 拜訪完
if p1 == m:
ans.append(nums2[p2])
p2 += 1
elif p2 == n:
ans.append(nums1[p1])
p1 += 1
# 比較兩陣列元素大小
elif nums1[p1] < nums2[p2]:
ans.append(nums1[p1])
p1 += 1
else:
ans.append(nums2[p2])
p2 += 1
# 保留 nums1 原本的記憶體位置
# 修改 nums1 的內容,讓它變成 ans 的結果
nums1[:] = ans
```
**複雜度**
* Time complexity: **O(m+n)**
* Space complexity: **O(m+n)**
---
**題解二**
* 思路:使用**逆向的雙指針**
* 優化:在合并 nums2 到 nums1 时,如果我们直接从前往后插入,就**会覆盖掉 nums1 还未处理的元素**。因此,我们 倒着填充 nums1 的最后位置,这样就不会破坏 nums1 还未处理的数据。
* 核心思路:
1. 设 p1 指向 nums1 的有效部分的最后一个元素(即==m-1==)。
2. 设 p2 指向 nums2 的最后一个元素(即==n-1==)。
3. 设 tail 指向 nums1 的最后一个位置(即==m+n-1==)。
从后往前填充 nums1,每次选 nums1[p1] 和 nums2[p2] 较大的那个放入 nums1[tail],然后指针前移。合併陣列 **ans**
```python=
class Solution:
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
# 指標初始化
p1, p2 = m - 1, n - 1
# 答案陣列 nums1 尾端索引
tail = m + n - 1
while p1 >= 0 or p2 >= 0:
# 特殊狀況 p1 或 p2 拜訪完
if p1 == -1:
nums1[tail] = nums2[p2]
p2 -= 1
elif p2 == -1:
nums1[tail] = nums1[p1]
p1 -= 1
# 比較兩陣列元素大小
elif nums1[p1] > nums2[p2]:
nums1[tail] = nums1[p1]
p1 -= 1
else:
nums1[tail] = nums2[p2]
p2 -= 1
# 每處理一個數字,tail 也要向左移
tail -= 1
```
**複雜度**
* Time complexity: **O(m+n)** 最差的狀況是,每個數都需移動一次
* Space complexity: **O(1)**,僅使用到一些額外變量
:::
:::spoiler Solution & Thinking(靈神官方思路)
**靈神題解**
* reference:[灵茶山艾府](https://leetcode.cn/problems/merge-sorted-array/solutions/2385610/dao-xu-shuang-zhi-zhen-wei-shi-yao-dao-x-xxkp/)
* 解題思路
1. nums1 有 m 個有效數字,nums2 有 n 個有效數字。
2. nums1 陣列的大小是 m + n,後面 n 個位置是空的,讓我們可以直接合併 nums2 進來。
3. **從後往前填充:** 因為兩個陣列都是排序好的,最大值一定在最後面,所以我們從 最大值開始放,避免覆蓋掉還沒處理的數據。
* 算法實現
1. 初始化三個指針:
* 指向 nums1: p1 = m-1
* 指向 nums2: p2 = n-1
* 指向 ans: p = m+n-1
2. 不斷比較 nums1[p1] 和 nums2[p2],比較大的放入nums1[p],循環直到 p < 0
```python=
from typing import List
class Solution:
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
# 指標初始化
p1, p2 = m - 1, n - 1
# 答案陣列尾端索引
tail = m + n - 1
while p2 >= 0: # nums2 還有要合併的元素
# nums1 還有要合併的元素 且 nums1[p1] > nums2[p2]
if p1 >= 0 and nums1[p1] > nums2[p2]:
nums1[tail] = nums1[p1]
p1 -= 1
else: # nums1[p1] <= nums2[p2] 或 p1 < 0
nums1[tail] = nums2[p2]
p2 -= 1
tail -= 1 # 下一個要填入的位置
```
**複雜度**
* Time complexity: **O(m+n)** 最差的狀況是,每個數都需移動一次
* Space complexity: **O(1)**,僅使用到一些額外變量
:::