給定兩個已排序整數數組 nums1 和 nums2,將 nums2 合併到 nums1 中使其成為一個有序數組。nums1 有足夠空間 (大小 ≥ m+n),前 m 個元素有效,nums2 有 n 個有效元素。要求原地修改 nums1,不返回新數組。
// 錯誤示範:從前往後填充會覆蓋 nums1 原有數據
int i=0, j=0, k=0;
while (i
利用 nums1 末尾的空閒空間,從最大元素開始比較,填充到 nums1 末尾,避免覆蓋未處理數據。
class Solution {
public:
void merge(vector& nums1, int m, vector& nums2, int n) {
int i = m - 1; // nums1 有效元素末尾
int j = n - 1; // nums2 有效元素末尾
int k = m + n - 1; // 合併後數組末尾
while (i >= 0 && j >= 0) {
if (nums1[i] > nums2[j]) {
nums1[k--] = nums1[i--];
} else {
nums1[k--] = nums2[j--];
}
}
// nums2 剩餘元素直接複製 (nums1 剩餘已在正確位置)
while (j >= 0) {
nums1[k--] = nums2[j--];
}
}
};
nums1 = [1,2,3,0,0,0], m=3 nums2 = [2,5,6], n=3 i=2(3), j=2(6), k=5 → 6>3 → nums1[5]=6, j=1, k=4 i=2(3), j=1(5), k=4 → 5>3 → nums1[4]=5, j=0, k=3 i=2(3), j=0(2), k=3 → 3>2 → nums1[3]=3, i=1, k=2 i=1(2), j=0(2), k=2 → 2=2 → nums1[2]=2, j=-1, k=1 j<0 結束,nums1 剩餘 [1,2] 已在正確位置 結果:[1,2,2,3,5,6]
| 關鍵點 | 說明 |
|---|---|
| 三指針 | i 指向 nums1 有效尾,j 指向 nums2 尾,k 指向合併尾 |
| 逆向填充 | 從大到小放置,利用 nums1 尾部空間,不覆蓋未讀數據 |
| 只需處理 nums2 剩餘 | 若 nums1 剩餘,本身就在正確位置無需移動 |
| 邊界條件 | m=0 或 n=0 直接返回/複製 |
public class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int i = m - 1, j = n - 1, k = m + n - 1;
while (i >= 0 && j >= 0) {
nums1[k--] = (nums1[i] > nums2[j]) ? nums1[i--] : nums2[j--];
}
// System.arraycopy(nums2, 0, nums1, 0, j+1); // 處理 nums2 剩餘
while (j >= 0) nums1[k--] = nums2[j--];
}
}
此「逆向填充」技巧廣泛適用於:
%20 (從後往前擴展)核心思想:當目標空間在源空間之後且有足夠緩衝區時,逆向處理避免數據覆蓋。