合并两个有序数组

Posted by zhouqian on Monday, June 13, 2022

力扣 88. 合并两个有序数组

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

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

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


方案一:临时数组计算保存结果,之后覆盖 nums1。

func merge(nums1 []int, m int, nums2 []int, n int)  {
    // 定义临时数组,将 nums1 和 nums2 的对比合并结果存入该临时数组
    res := make([]int, m + n)
    // i, j 分别指向 nums1 和 nums2 的数组开头,k 指向临时数组开头
    for i, j, k := 0, 0, 0; k < m + n; k++ {
        // 对比 i,j 指向的值,将较大者存入 k 指向的位置,同时更新 i,j 位置
        if j >= n || i < m && nums1[i] < nums2[j] {
            res[k] = nums1[i]
            i++
        } else {
            res[k] = nums2[j]
            j++
        }
    }
    
    // 将临时数组的值覆写到 nums1
    for i, num := range res {
        nums1[i] = num
    }
}
  • 时间复杂度:O(m+n),因为需要遍历所有数组元素才能完成元素比较,合并数组,所以时间复杂度为 O(m+n)。
  • 空间复杂度:O(m+n),因为使用了一个长度为 m+n 的临时数组保存合并结果,最后再将临时数组结果覆盖到原数组,所以空间复杂度为 O(m+n)。

方案二:逆向思维,反向计算。

func merge(nums1 []int, m int, nums2 []int, n int)  {
    // 因为 nums1 的下标从 m 开始后对应的值都为 0
    // 将 nums1 和 nums2 从数组尾部进行对比
    // 并将较大值写入 nums1 的尾部可以不对 nums1 前面的值造成干扰
    // i, j 分别指向 nums1 和 nums2 的最大值,k 指向 nums1 的最大允许下标
    for i, j, k := m - 1, n - 1, m + n - 1; k >= 0; k-- {
        // 对比 nums1 和 nums2 的最大值,并将结果写入 k 指向的位置,从后到前完成遍历
        if j < 0 || i >= 0 && nums1[i] > nums2[j] {
            nums1[k] = nums1[i]
            i--
        } else {
            nums1[k] = nums2[j]
            j--
        }
    }
}
  • 时间复杂度:O(m+n),因为需要遍历所有数组元素才能完成元素比较,合并数组,所以时间复杂度为 O(m+n)。
  • 空间复杂度:O(1),因为所有的元素比较移动操作都在数组 nums1 中完成,没有借助额外的辅助空间,所以空间复杂度为 O(1)。