1. 题目解析与核心思路
- 移动零是LeetCode Hot100系列中的一道经典数组操作题。题目要求将一个包含零的整数数组中的所有零移动到数组末尾,同时保持非零元素的相对顺序不变。看似简单的需求背后,隐藏着对数组操作基本功的全面考察。
1.1 题目要求详解
给定一个整数数组nums,我们需要实现原地(in-place)的修改操作:
- 所有非零元素保持原有顺序
- 所有零元素被移动到数组末尾
- 不能创建新数组作为返回结果
- 尽量减少操作次数(最优解时间复杂度O(n))
示例:
输入:[0,1,0,3,12]
输出:[1,3,12,0,0]
1.2 关键难点分析
这道题的核心挑战在于三个约束条件的平衡:
- 原地操作的限制排除了创建新数组的简单解法
- 保持非零元素顺序要求我们不能使用排序等会打乱原始顺序的方法
- 时间复杂度限制迫使我们寻找线性解法
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 解法思路与算法选择
2.1 暴力解法与优化方向
最直观的暴力解法是遇到零就将其与后面的元素逐个交换,直到零被移动到末尾。这种方法虽然简单,但时间复杂度会达到O(n²),在长数组情况下性能堪忧。
优化思路在于减少不必要的交换操作。我们可以通过记录非零元素应该放置的位置,最后统一处理零的填充,这样可以将时间复杂度优化到O(n)。
2.2 双指针法的应用
高效解法通常采用双指针技巧:
- 慢指针(slow):记录下一个非零元素应该放置的位置
- 快指针(fast):遍历数组寻找非零元素
具体操作流程:
- 初始化slow=0
- fast从0开始遍历数组
- 当nums[fast]≠0时,将其赋值给nums[slow],然后slow++
- 遍历结束后,将slow之后的所有位置赋值为0
这种解法只需要一次遍历和最后的补零操作,完美满足题目所有要求。
3. 代码实现与细节优化
3.1 Python标准实现
python复制def moveZeroes(nums):
slow = 0
for fast in range(len(nums)):
if nums[fast] != 0:
nums[slow] = nums[fast]
slow += 1
for i in range(slow, len(nums)):
nums[i] = 0
3.2 优化版本(减少赋值操作)
我们可以进一步优化,在遍历过程中直接完成交换,避免最后的补零循环:
python复制def moveZeroes(nums):
slow = 0
for fast in range(len(nums)):
if nums[fast] != 0:
nums[slow], nums[fast] = nums[fast], nums[slow]
slow += 1
这种实现虽然代码更简洁,但实际运行时会因为更多的交换操作而略微影响性能,在面试时可以讨论两种实现的优劣。
4. 复杂度分析与边界情况
4.1 时间复杂度分析
两种实现的时间复杂度都是O(n):
- 第一种:一次遍历+一次补零循环,都是O(n)
- 第二种:单次遍历完成所有操作,O(n)
空间复杂度都是O(1),符合原地操作的要求。
4.2 边界情况处理
需要特别注意的边界情况包括:
- 空数组输入:应直接返回
- 全零数组:保持原样即可
- 全非零数组:不应有任何修改
- 单元素数组:直接返回
我们的实现在这些情况下都能正确处理。
5. 测试用例设计与验证
5.1 基础测试用例
python复制# 常规情况
assert moveZeroes([0,1,0,3,12]) == [1,3,12,0,0]
# 无零情况
assert moveZeroes([1,2,3]) == [1,2,3]
# 全零情况
assert moveZeroes([0,0,0]) == [0,0,0]
5.2 极端情况测试
python复制# 空数组
assert moveZeroes([]) == []
# 单元素非零
assert moveZeroes([1]) == [1]
# 单元素为零
assert moveZeroes([0]) == [0]
6. 同类题型与扩展思考
6.1 相似题目推荐
掌握了移动零的思路后,可以尝试解决以下类似问题:
-
- 移除元素(同样使用双指针)
-
- 删除有序数组中的重复项
-
- 删除有序数组中的重复项 II
6.2 变种问题思考
如果题目要求变为:
- 将零移动到数组开头
- 保持零的相对顺序不变
- 将特定值(而非零)移动到末尾
这些变种都可以通过调整双指针的逻辑来解决,体现了算法思想的灵活性。
7. 面试技巧与注意事项
7.1 面试常见考察点
面试官通常会关注:
- 能否快速识别出双指针的应用场景
- 对原地操作要求的理解深度
- 边界条件的考虑是否全面
- 代码的简洁性与可读性
7.2 代码优化建议
在面试中可以:
- 先给出暴力解法,再逐步优化
- 讨论不同实现方式的trade-off
- 主动提出测试用例验证代码
- 分析时间/空间复杂度
8. 实际应用场景
虽然看似简单,但这种数组重排的思想在实际开发中有广泛应用:
- 数据库记录过滤与重组
- 游戏开发中的对象排序
- 大数据处理中的前置过滤
- 内存压缩算法的基础操作
理解这类基础算法问题,有助于培养解决复杂工程问题的底层思维能力。
