- Published on
 
LeetCode-88.合并两个有序数组
- Authors
 
- Name
 - Piggy DP
 - @xiaozhudxiaozhu
 
✨ 题目介绍
给你两个 升序排列 的整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使得 nums1 成为一个升序数组。
- 初始时,
nums1的长度为m + n,其中前m个元素为有效元素,后n个元素为 0(占位)。 nums2的长度为n。
你需要 就地修改 nums1,不能返回新数组。
LeetCode 中的经典题目:88. Merge Sorted Array
💡 题目思路
我们可以使用双指针归并排序思想,维护两个指针分别指向 nums1 和 nums2 的当前比较元素。
- 指针 
i初始指向nums1的第一个有效元素 - 指针 
j初始指向nums2的第一个元素 - 比较两者的大小,较小的元素放入新的位置数组 
mergedArray - 最后将 
mergedArray复制回nums1 
注意:
- 原地合并(不借助额外数组)的方法会更优,本文在“优化方案”部分介绍。
 
🧮 思路演示
举个例子:
nums1 = [1,3,5,0,0,0], m = 3
nums2 = [2,4,6], n = 3
合并步骤如下:
- 比较 1 和 2,取 1
 - 比较 3 和 2,取 2
 - 比较 3 和 4,取 3
 - 比较 5 和 4,取 4
 - 比较 5 和 6,取 5
 - nums2 还剩 6,放入
 
最终:nums1 = [1,2,3,4,5,6]
💻 题目代码实现(含测试)
import java.util.Arrays;
public class ProblemMergeSortedArray {
    public static void merge(int[] nums1, int m, int[] nums2, int n) {
        if (nums1 == null || nums2 == null) {
            throw new IllegalArgumentException("Input arrays must not be null!");
        }
        if (m < 0 || n < 0) {
            throw new IllegalArgumentException("Length parameters must be non-negative!");
        }
        if (m + n > nums1.length) {
            throw new IllegalArgumentException("nums1 Length is insufficient to hold merged result!");
        }
        if (m > nums1.length || n > nums2.length) {
            throw new IllegalArgumentException("Length parameter exceed actual array length!");
        }
        int nums1Index = 0, nums2Index = 0, mergedIndex = 0;
        int[] mergedArray = new int[m + n];
        while (nums1Index < m && nums2Index < n) {
            if (nums1[nums1Index] < nums2[nums2Index]) {
                mergedArray[mergedIndex++] = nums1[nums1Index++];
            } else {
                mergedArray[mergedIndex++] = nums2[nums2Index++];
            }
        }
        while (nums1Index < m) {
            mergedArray[mergedIndex++] = nums1[nums1Index++];
        }
        while (nums2Index < n) {
            mergedArray[mergedIndex++] = nums2[nums2Index++];
        }
        System.arraycopy(mergedArray, 0, nums1, 0, m + n);
    }
    public static void testMerge(String testName, int[] nums1, int m, int[] nums2, int n, int[] expected) {
        System.out.println("=== Test Case: " + testName + " ===");
        try {
            int[] originalNums1 = nums1 != null ? Arrays.copyOf(nums1, nums1.length) : null;
            if (expected == null) {
                try {
                    merge(nums1, m, nums2, n);
                    System.out.println("FAIL - Expected exception but none thrown");
                } catch (Exception e) {
                    System.out.println("PASS - Caught expected exception: " + e.getClass().getSimpleName() + " - " + e.getMessage());
                }
            } else {
                merge(nums1, m, nums2, n);
                if (Arrays.equals(nums1, expected)) {
                    System.out.println("PASS");
                } else {
                    System.out.println("FAIL");
                }
                System.out.println("Input nums1: " + Arrays.toString(originalNums1) + ", m: " + m);
                System.out.println("Input nums2: " + Arrays.toString(nums2) + ", n: " + n);
                System.out.println("Expected:    " + Arrays.toString(expected));
                System.out.println("Actual:      " + Arrays.toString(nums1));
            }
        } catch (Exception e) {
            System.out.println("FAIL - Unexpected exception: " + e.getMessage());
        }
    }
    public static void main(String[] args) {
        // ✅ 正常情况测试
        testMerge("Both arrays with elements",
                new int[]{1, 3, 5, 0, 0, 0}, 3,
                new int[]{2, 4, 6}, 3,
                new int[]{1, 2, 3, 4, 5, 6});
        testMerge("nums1 empty",
                new int[]{0, 0, 0}, 0,
                new int[]{2, 4, 6}, 3,
                new int[]{2, 4, 6});
        testMerge("nums2 empty",
                new int[]{1}, 1,
                new int[]{}, 0,
                new int[]{1});
        testMerge("All elements same",
                new int[]{2, 2, 2, 0, 0}, 3,
                new int[]{2, 2}, 2,
                new int[]{2, 2, 2, 2, 2});
        testMerge("With duplicates",
                new int[]{1, 2, 3, 0, 0, 0}, 3,
                new int[]{2, 5, 6}, 3,
                new int[]{1, 2, 2, 3, 5, 6});
        // ❌ 异常情况测试
        testMerge("nums1 is null", null, 0, new int[]{1, 2}, 2, null);
        testMerge("nums2 is null", new int[]{1, 2, 0}, 2, null, 1, null);
        testMerge("m is negative", new int[]{1, 2, 0}, -1, new int[]{3}, 1, null);
        testMerge("n is negative", new int[]{1, 2, 0}, 2, new int[]{3}, -1, null);
        testMerge("nums1 too short", new int[]{1, 2}, 2, new int[]{3, 4}, 2, null);
        testMerge("m exceeds nums1 length", new int[]{1, 2}, 3, new int[]{3}, 1, null);
        testMerge("n exceeds nums2 length", new int[]{1, 2, 0}, 2, new int[]{3}, 2, null);
    }
}
⏱️ 时间和空间复杂度分析
- 时间复杂度:O(m + n) 每个元素都只遍历了一次。
 - 空间复杂度:O(m + n) 使用了一个额外数组 
mergedArray存储合并结果。 
🚀 算法优化方案(更好的写法)
题目要求在 nums1 原地修改。我们可以 从后往前遍历,这样就能直接在 nums1 中放置最大元素,无需额外数组:
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--];
    }
    while (j >= 0) {
        nums1[k--] = nums2[j--];
    }
}
- 时间复杂度仍为 O(m + n)
 - 空间复杂度为 O(1),无需额外数组
 
✅ 总结
- 本题本质是归并排序的合并过程。
 - 初始写法逻辑清晰但使用了额外数组,可以作为理解算法的第一步。
 - 最终推荐使用从后向前原地合并的方法,提升空间效率。