在日常刷题和面试中,「合并两个有序数组」是一个经典基础题。虽然属于简单难度,但它非常考察你的数组操作技巧和代码优化能力。本篇文章将带你从基础解法入手,进阶到最简洁的三元表达式写法,理解每一行代码背后的逻辑。
给你两个按 非递减顺序 排列的整数数组
nums1和nums2,另有两个整数m和n,分别表示这两个数组中有效的元素个数。 请你将nums2合并到nums1中,使合并后的数组仍然按 非递减顺序 排列。
约定:
nums1 的长度为 m + n,前 m 个元素是有效数据,后 n 个是 0(占位符,用于合并)。nums2 的长度为 n,且所有数据都是有效的。我们采用 倒序三指针法:
i 指向 nums1 的有效部分末尾(即 m - 1);j 指向 nums2 的末尾(即 n - 1);k 指向 nums1 的最后(即 m + n - 1),准备从这里倒着填充最大值。这样做的关键好处是:不需要移动 nums1 中已有的元素,从而提升效率,避免不必要的操作。
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 i >= 0 and j >= 0:
nums1[k], i, j = (nums1[i], i - 1, j) if nums1[i] > nums2[j] else (nums2[j], i, j - 1)
k -= 1
nums1[:j + 1] = nums2[:j + 1]i, j, k = m - 1, n - 1, m + n - 1i 指向 nums1 的最后一个有效元素j 指向 nums2 的最后一个元素k 指向合并后数组的最后一个位置while i >= 0 and j >= 0:
nums1[k], i, j = (nums1[i], i - 1, j) if nums1[i] > nums2[j] else (nums2[j], i, j - 1)
k -= 1这是代码的核心逻辑,用了一行三元表达式简洁完成以下步骤:
nums1[i] 和 nums2[j],将较大的元素放入 nums1[k]k -= 1 每次填充后向前移动一位❗ 注意:
nums1[k], i, j = ...是 Python 中同时赋值的语法,它保证在一行中完成所有更新。
nums1[:j + 1] = nums2[:j + 1]为什么是 j + 1?
[:j + 1] 表示从 0 到 j(包含 j)的位置。nums1 的元素全部更大,nums2 的部分没被填进去,那就直接复制剩下的部分到 nums1 的前面。nums1 = [1, 2, 3, 0, 0, 0]
m = 3
nums2 = [2, 5, 6]
n = 3初始:
i=2, j=2, k=5
比较 nums1[2]=3 和 nums2[2]=6 → 填入 nums1[5]=6,j--
比较 nums1[2]=3 和 nums2[1]=5 → 填入 nums1[4]=5,j--
比较 nums1[2]=3 和 nums2[0]=2 → 填入 nums1[3]=3,i--
比较 nums1[1]=2 和 nums2[0]=2 → 填入 nums1[2]=2,j--
比较 nums1[1]=2 和 nums2[-1]=越界 → 循环结束
最后复制剩余 nums2[:0+1] → nums2[0] → nums1[0]最终输出:
[1, 2, 2, 3, 5, 6]指标 | 说明 |
|---|---|
时间复杂度 | O(m + n) — 每个元素最多处理一次 |
空间复杂度 | O(1) — 原地合并,不用额外空间 |
这题是数组类题目中的高频面试题:
[:j+1] 的切片语法是关键细节之一。写法 | 可读性 | 简洁性 | 面试推荐 |
|---|---|---|---|
标准 if/else 写法 | ✅ 高 | ❌ 稍长 | ✅ 推荐 |
三元表达式写法 | ❌ 稍低 | ✅ 极简 | ✅ 可选(加注释更好) |