题目描述
原地把数组里所有 0 移到末尾,非零元素保持原来顺序。
思路解析
每遇到一个 0 就把后面元素整体前移,最坏要移 n² 次。换个思路:让非零元素一个个「向前归位」,0 自然就留在后面了。
fast 一路向前找非零;每找到一个,就和 slow 位置交换,slow 前进一格。因为 fast 是从左到右按原顺序遇到非零的,依次写入 slow,相对顺序天然不变;slow 左边永远是「已归位的非零」,最后空出来的位置自然是 0。
slow=0, fast=0:fast 当前是 0,不处理,fast 往前走,slow 停在 0 等一个非零。
fast=1 · 遇 1:fast 找到非零 1,和 slow(0号位)交换。1 归位到最前,slow 前进到 1。
fast=2 · 遇 0:fast 是 0,跳过。slow 停在 1 号位等下一个非零。
fast=3 · 遇 3:fast 找到 3,和 slow(1号位)交换:3 归位,slow 前进到 2。
fast=4 · 遇 12:fast 找到 12,和 slow(2号位)交换:12 归位,slow 前进到 3。
完成:fast 走完,slow 左边 [1,3,12] 全是归位的非零,后面自然剩下两个 0:[1,3,12,0,0]。
slow 是「写指针」、fast 是「读指针」——读到合格的就写到 slow 并前进。删除元素、去重都是这套快慢指针。
参考代码(Python)
1slow = 0
2for fast in range(len(nums)):
3 if nums[fast] != 0: # 找到非零
4 nums[slow], nums[fast] = nums[fast], nums[slow]
5 slow += 1 # 归位一个复杂度分析
- 时间复杂度:O(n) —— fast 扫一遍
- 空间复杂度:O(1) —— 原地交换
套路模板
记住骨架:fast 读、slow 写、合格才写并进位。删除有序数组重复项、移除元素都是改一下「保留」条件。
1# 「原地保留/移动符合条件的元素」都套
2slow = 0 # 写指针
3for fast in range(n): # 读指针
4 if 保留(nums[fast]): # 合格就写入
5 nums[slow] = nums[fast]; slow += 1
6# slow 左边就是结果,长度 = slow易错点
- ❌ 直接把非零覆盖、不管 0 → ✅ 用交换或最后补 0(覆盖会丢掉本该留到末尾的 0)
- ❌ slow 每轮都 +1 → ✅ 只有写入时才 slow += 1(slow 只在放入合格元素后前进)
以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握。