给你两个按非递减顺序排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n,分别表示 nums1 和 nums2 中的有效元素个数。
请你合并 nums2 到 nums1 中,使合并后的数组同样按非递减顺序排列。
注意:最终合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0,应忽略。nums2 的长度为 n。
示例:
本题要求合并两个已经有序的数组,并且必须把结果原地写回 nums1。
如果从前往后合并,nums1 前面的有效元素可能会被提前覆盖,导致原始数据丢失。由于 nums1 后面预留了 n 个空位,所以可以从后往前放入较大的元素。
这是一道典型的双指针题:分别从 nums1 和 nums2 的有效尾部开始比较,每次把较大的数放到 nums1 当前最后一个待填位置。
使用三个指针:
p1:指向 nums1 有效元素的最后一个位置,初始为 m - 1。p2:指向 nums2 最后一个位置,初始为 n - 1。tail:指向 nums1 当前要写入的位置,初始为 m + n - 1。当前待合并的有效区间是:
nums1[0...p1]nums2[0...p2]nums1[tail] 是下一次要填入最终结果的位置。
每次比较 nums1[p1] 和 nums2[p2]:
nums1[p1] > nums2[p2],说明 nums1[p1] 是当前两个数组剩余元素中的最大值,把它写入 nums1[tail],然后 p1--。nums2[p2] 写入 nums1[tail],然后 p2--。tail--,表示下一个位置继续向前填。因为两个数组本身有序,从尾部取较大值放到最终数组尾部,不会影响还没比较的元素。
本题没有单独的返回值,答案就是被原地修改后的 nums1。
每一轮比较后,都把当前最大值写入 nums1[tail],这一步就是在更新答案数组。
当 p2 < 0 时,说明 nums2 已经全部合并完成,nums1 中剩余元素本来就在正确位置,可以直接结束。
当 p1 < 0 但 p2 >= 0 时,说明 nums1 的有效元素已经用完,需要继续把 nums2 剩余元素写入 nums1 前面的位置。
边界条件:
n = 0,nums2 为空,nums1 不需要修改。m = 0,nums1 没有有效元素,需要把 nums2 全部复制进 nums1。易错点:
nums1,否则可能覆盖 nums1 中还没比较的有效元素。p2 >= 0。如果 nums2 合并完,nums1 剩余元素已经天然有序,不必继续处理。tail 每次写入后都要左移,否则会反复覆盖同一个位置。O(m + n),每个指针都只会向左移动,两个数组的元素最多各处理一次。O(1),只使用了常数个额外变量,合并结果直接写回 nums1。