文章

88.合并两个有序数组

题目说明

难度简单

给你两个按 非递减顺序 排列的整数数组 nums1 **和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。

请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序** 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

示例 1:

1
2
3
4
5
输入: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:

1
2
3
4
5
输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
解释:需要合并 [1] 和 [] 。
合并结果是 [1] 。

示例 3:

1
2
3
4
5
6
输入:nums1 = [0], m = 0, nums2 = [1], n = 1
输出:[1]
解释:需要合并的数组是 [] 和 [1] 。
合并结果是 [1] 。
注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。

提示:

  • nums1.length == m + n
  • nums2.length == n
  • 0 <= m, n <= 200
  • 1 <= m + n <= 200
  • 109 <= nums1[i], nums2[j] <= 109

解题思路

这是一道常见的双指针问题,我们可以使用两个指针分别指向两个有序数组的末尾,然后不断比较两个指针所指向的数大小,并将其中较大的数插入到一个新的数组中。

  1. 初始化指针:设置三个指针 ijk,其中 i 指向 nums1 数组的最后一个元素,j 指向 nums2 数组的最后一个元素,k 指向 nums1 数组末尾的空位(即 m + n - 1,因为 nums1 的前 m 个元素已经存在,需要在它们后面插入 nums2 的元素)。

  2. 合并过程:使用 while 循环,只要 ij 都大于等于0(即两个数组都还有元素未比较),就进行以下操作:
    • 比较 nums1[i]nums2[j] 的大小。
    • 如果 nums1[i] 大于 nums2[j],则将 nums1[i] 移动到 nums1[k] 的位置,并将 ik 都向前移动一位。
    • 如果 nums1[i] 小于或等于 nums2[j],则将 nums2[j] 移动到 nums1[k] 的位置,并将 jk 都向前移动一位。
  3. 处理剩余元素:当 nums2 数组的所有元素都被比较过后,如果 nums1 数组还有剩余的元素未比较(即 i < 0),则 nums2 中剩余的元素直接插入到 nums1 的前面。这部分通过另一个 while 循环完成,循环条件是 j >= 0,循环体是将 nums2[j] 插入到 nums1[k],同时 jk 向前移动一位。

  4. 结束函数:由于 nums1inout 参数,所以对它的修改会直接反映到原数组上,不需要额外的返回值。函数没有显式返回语句,因为在 Swift 中,最后一行表达式的值会被用作函数的返回值,但在这个函数中,没有需要返回的值。

这个函数的时间复杂度是 O(n),其中 n 是 nums2 的长度,因为每个元素最多被比较一次。空间复杂度是 O(1),因为除了输入数组外,没有使用额外的存储空间。

代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func merge(_ nums1: inout [Int], _ m: Int, _ nums2: [Int], _ n: Int) {
    var i = m - 1 // 初始化 nums1 数组指针 i,指向数组最后一个数
    var j = n - 1 // 初始化 nums2 数组指针 j,指向数组最后一个数
    var k = m + n - 1 // 初始化 nums1 数组需要插入元素的下标 k,指向数组最后一个空位

    while i >= 0 && j >= 0 { // 只要两个数组都还没遍历完
        if nums1[i] > nums2[j] { // 如果 nums1 当前指向的数比 nums2 当前指向的数大
            nums1[k] = nums1[i] // 将 nums1 当前指向的数插入到 nums1 数组的最后
            i -= 1 // nums1 指针左移一位
        } else {
            nums1[k] = nums2[j] // 将 nums2 当前指向的数插入到 nums1 数组的最后
            j -= 1 // nums2 指针左移一位
        }
        k -= 1 // 插入元素的下标左移一位
    }

    // 如果 nums2 数组还有剩余的元素没有被插入到 nums1 中,则将其全部插入到 nums1 的前面
    while j >= 0 {
        nums1[k] = nums2[j]
        j -= 1
        k -= 1
    }
}
本文由作者按照 CC BY 4.0 进行授权