LeetCode: 88. 合并两个有序数组(swift)

100 阅读2分钟

88. 合并两个有序数组

难度简单

给你两个按 非递减顺序 排列的整数数组 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 中。
​

提示:

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

解题思路

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

因为本题要求我们将结果保存在第一个数组 nums1 中,所以不能使用额外的空间。

但是由于 nums1 数组后面有很多空位,因此可以从后往前遍历两个数组,利用 nums1 的后面的空位来存放最终的结果。

具体地,我们可以定义三个指针 ijk,分别指向 nums1nums2nums1 需要插入元素的下标。

  1. 初始化指针 i 指向 nums1 的最后一个有值的数,即 m - 1

    1. 指针 j 指向 nums2 的最后一个有值的数,即 n - 1
    2. 指针 k 指向 nums1 数组需要插入元素的下标,即 m + n - 1
    3. 指针 ij 的初始值都是最后一个有值的数,而指针 k 的初始值是最后一个空位的下标。
  2. 不断比较 nums1nums2 当前指向的数,将其中较大的数插入到 nums1 数组的末尾,并将指针向前移动一位。

    1. 使用一个 while 循环,在循环体内部比较 nums1[i]nums2[j] 的大小,
    2. 如果 nums1[i] 大于 nums2[j],则将 nums1[i] 插入到 nums1 数组的末尾(即 nums1[k] = nums1[i]),并将指针 i 向前移动一位(即 i -= 1)。
    3. 否则,将 nums2[j] 插入到 nums1 数组的末尾(即 nums1[k] = nums2[j]),并将指针 j 向前移动一位(即 j -= 1)。
    4. 在每次插入元素之后,指针 k 也需要向前移动一位(即 k -= 1)。
  3. 如果 nums2 数组还有剩余的元素没有被插入到 nums1 中,则将其全部插入到 nums1 的前面。这是因为如果 nums1 数组先遍历完,而 nums2 数组还有剩余元素未插入到 nums1 中,那么这些元素肯定是小于 nums1 数组中已经遍历过的所有数的,因此可以直接插入到 nums1 数组的前面。

代码实现:

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
    }
}