双指针原地交换法可高效实现零元素移至末尾:left指向非零元素应放位置,right遍历数组,遇非零则与left交换并右移left,时间复杂度o(n),空间复杂度o(1)。

把数组中的所有零元素移动到末尾,同时保持非零元素的相对顺序,关键在于 不使用额外空间 且 只遍历一次。最常用、最高效的方法是双指针原地交换。
用双指针一次遍历完成移动
维护两个指针:left 指向下一个非零元素应该放置的位置(从 0 开始),right 遍历整个数组。当 right 遇到非零数,就把它和 left 位置交换,然后 left 向后移一位。
- 这样能保证所有非零数按原序紧凑排在前面,left 之后自然全是零(无需手动填零)
- 时间复杂度 O(n),空间复杂度 O(1)
- 代码简洁稳定,适用于含正数、负数、零的任意整数数组
PHP 实现示例
以下是一个可直接运行的函数:
function moveZeroes(&$nums) {
$left = 0;
for ($right = 0; $right < count($nums); $right++) {
if ($nums[$right] !== 0) {
if ($left !== $right) {
$temp = $nums[$left];
$nums[$left] = $nums[$right];
$nums[$right] = $temp;
}
$left++;
}
}
}
调用方式:$arr = [0, 1, 0, 3, 12]; moveZeroes($arr); // 结果:[1, 3, 12, 0, 0]
立即学习“PHP免费学习笔记(深入)”;
注意边界与常见误区
- 务必使用
&$nums引用传参,否则修改不会反映到原数组 - 交换前判断
$left !== $right可避免自交换,虽不影响结果但更严谨 - 不要用
==判断零,应使用!== 0,防止把false或空字符串误判为零(若数组类型混合需另作处理) - 不推荐先过滤再合并(如
array_merge(array_filter(...), array_fill(...))),会创建新数组,违背“原地”要求
扩展:仅统计零个数的轻量做法
如果业务只要求“效果等价”而不要求严格原地交换(例如输出新数组也可接受),可用更直观的方式:
- 遍历一次,收集所有非零元素;再补足对应数量的零
- 适合脚本快速处理、测试或数据量小的场景
- 代码短但空间复杂度升为 O(n),不满足算法题进阶要求











