在问 · 算法题解

88. 合并两个有序数组

题目描述

输入两个非递减的整数数组 nums1、nums2,以及整数 m、n。nums1 的前 m 个元素是有效数据,后 n 个位置是占位用的 0,应当忽略;nums2 恰好有 n 个元素。

把 nums2 并入 nums1,使 nums1 的全部 m + n 个元素仍然非递减。

结果直接写在 nums1 里,函数不返回值。示例输出展示的是合并后的 nums1。

示例 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] 合并。

示例 2
输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]

解释:nums2 为空,nums1 不变。

示例 3
输入:nums1 = [0], m = 0, nums2 = [1], n = 1
输出:[1]

解释:m = 0,nums1 里的 0 只是占位,合并后就是 [1]。

数据范围

  • nums1.length == m + n
  • nums2.length == n
  • 0 <= m, n <= 200
  • 1 <= m + n <= 200
  • -10^9 <= nums1[i], nums2[j] <= 10^9

进阶:能否在 O(m + n) 时间内完成?

解题思路

从后往前填。i 指向 nums1 有效部分的末尾,j 指向 nums2 末尾,k 指向 nums1 最后一个位置。每次把 nums1[i] 和 nums2[j] 中较大的放到 nums1[k],对应指针和 k 各左移一位。nums2 放完就结束,nums1 剩下的元素已经在正确位置。

为什么正确

nums1[k+1:] 是全体元素中最大的 m+n−k−1 个,已排好序;并且 k = i + j + 1,所以写入 nums1[k] 不会覆盖还没读的 nums1[i]。

复杂度分析

时间 O(m + n),空间 O(1)。

易错点

从前往后合并会覆盖 nums1 中还没读的元素。循环条件写 j >= 0 即可;若写成 i >= 0 and j >= 0,要记得把 nums2 剩余的元素补进去。m = 0 时 i 一开始就是 -1。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        i, j, k = m - 1, n - 1, m + n - 1
        while j >= 0:
            if i >= 0 and nums1[i] > nums2[j]:
                nums1[k] = nums1[i]
                i -= 1
            else:
                nums1[k] = nums2[j]
                j -= 1
            k -= 1

载入编辑器,自己跑一遍 →

双指针 专题的其他题目

查看 双指针 全部题目 →