🔗 移动零
📌 题目描述
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
请注意,必须在不复制数组的情况下原地对数组进行操作。
✅ 示例解析
示例 1:
- 输入:
nums = [0, 1, 0, 3, 12]
- 输出:
[1, 3, 12, 0, 0]
- 解释:所有非零元素
1, 3, 12
保持原有顺序,所有0
被移动到数组末尾。
示例 2:
- 输入:
nums = [0]
- 输出:
[0]
- 解释:数组中只有一个元素,且为
0
,因此无需移动。
示例 3:
- 输入:
nums = [1, 0, 2, 0, 3]
- 输出:
[1, 2, 3, 0, 0]
- 解释:非零元素
1, 2, 3
按原顺序排列,两个0
被移到末尾。
⚠️ 提示
1 <= nums.length <= 10⁴
-2³¹ <= nums[i] <= 2³¹ - 1
要求:在原数组上操作,不能复制数组。
💡 解法:双指针法(快慢指针)—— O(n) 时间,O(1) 空间
class Solution {
public void moveZeroes(int[] nums) {
int index = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] != 0) {
int temp = nums[i];
nums[i] = nums[index];
nums[index] = temp;
index++;
}
}
}
}
📊 复杂度分析
- 时间复杂度:O(n)
只需一次遍历数组,每个元素最多被访问一次,交换操作为常数时间。 - 空间复杂度:O(1)
只使用了常数额外空间(index
和temp
变量),满足原地操作要求。
🧩 解题思路
- 双指针思想:
- 定义一个慢指针
index
,表示下一个非零元素应放置的位置。 - 使用快指针
i
遍历整个数组。
- 定义一个慢指针
- 核心逻辑:
- 当遇到非零元素时,将其与
index
位置的元素交换(或将值赋给index
位置),然后index++
。 - 这样可以保证所有非零元素按顺序被“挤”到数组前端。
- 当遇到非零元素时,将其与
- 为什么能保持相对顺序? 因为快指针从左到右遍历,非零元素按出现顺序依次被放置在
index
位置,因此它们的相对顺序不变。 - 0 自然后移: 所有非零元素被前移后,剩下的位置自然由
0
填充,无需额外操作。