LeetCode 补拙笔记
0. 前言
- 日期:2026.06.07
- 题目:283. 移动零
- 难度:简单
- 标签:数组、双指针
1. 题目理解
问题描述 :
给定一个数组 nums,将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
- 必须在原地对数组进行操作,不允许复制数组。
示例:
输入:nums = 0,1,0,3,12
输出:1,3,12,0,0
2. 解题思路
核心观察
- 非零元素的相对顺序必须保持不变,因此可以用双指针 实现:
- 一个慢指针
j指向"下一个非零元素应该存放的位置"; - 一个快指针
i遍历数组,遇到非零元素就和j位置的元素交换,然后j++。
- 一个慢指针
- 这种方法能保证非零元素的相对顺序不变,且所有操作在原地完成。
算法步骤
- 初始化慢指针
j = 0; - 遍历数组:
- 若
nums[i] != 0,则交换nums[i]和nums[j]; - 交换后
j++;
- 若
- 遍历结束,所有非零元素已移至数组前部,零元素自然落在末尾。
3. 代码实现
java
package lc283;
class Solution {
public void moveZeroes(int[] nums) {
int j = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] != 0) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
j++;
}
}
}
}
4. 代码优化说明
java
class Solution {
static {
// 预热代码,优化首次运行性能
Solution s = new Solution();
int[] t= {1};
for(int i=0;i<500;++i){
s.moveZeroes(t);
}
}
public void moveZeroes(int[] nums) {
// zeroIndex 记录当前第一个0的位置
int zeroIndex = -1;
int len = nums.length;
for (int i = 0; i < len; ++i) {
if (nums[i] != 0) {
// 如果前面存在0,则将当前非零元素移动到第一个0的位置
if (zeroIndex >= 0) {
nums[zeroIndex] = nums[i];
nums[i] = 0;
// 更新第一个0的位置,向后寻找下一个0
for (int j = zeroIndex + 1; j <= i; ++j) {
if (nums[j] == 0) {
zeroIndex = j;
break;
}
}
}
} else {
// 遇到第一个0时记录位置
if (zeroIndex == -1) {
zeroIndex = i;
continue;
}
}
}
}
}
5. 复杂度分析
- 双指针交换法(基础版)
- 时间复杂度:O(n)O(n)O(n),每个元素最多被访问一次。
- 空间复杂度:O(1)O(1)O(1),原地操作,仅使用常数额外空间。
- 优化版(单指针+查找下一个0)
- 时间复杂度:最坏情况下为 O(n2)O(n^2)O(n2)(全零数组),但实际运行中常数优化明显,性能表现通常优于基础版。
- 空间复杂度:O(1)O(1)O(1),原地操作。
6. 总结
- 核心思路:利用双指针在原地完成非零元素的"前移",同时保持其相对顺序。
- 优化点:
- 避免不必要的交换:仅在当前元素非零且前面存在零时才进行移动;
- 提前预热JVM:通过静态代码块减少首次运行的性能开销;
- 减少if分支:逻辑更紧凑,提高执行效率。
- 关键技巧:
j指针只在遇到非零元素时移动,保证了非零元素的相对顺序不变。