283. 移动零
题目描述
输入一个整数数组 nums。
把数组里所有的 0 都挪到末尾,非零元素之间的先后顺序要保持不变。
必须直接在原数组上修改,不能另外复制一份数组。函数无需返回值,判题时检查修改后的 nums。
示例 1
输入:nums = [0,1,0,3,12] 输出:[1,3,12,0,0]
解释:非零元素 1,3,12 保持原顺序排在前面,两个 0 移到末尾。
示例 2
输入:nums = [0] 输出:[0]
解释:只有一个 0,数组不变。
数据范围
1 <= nums.length <= 10^4-2^31 <= nums[i] <= 2^31 - 1
进阶:能否让总的操作次数尽可能少?
解题思路:双指针交换
write 指向下一个非零应放的位置。扫描 read,遇到非零就与 write 位置交换并递增 write;扫描结束后零自然集中在尾部。
为什么正确
每轮结束时,nums[:write] 已是按原顺序收集的全部非零元素。
复杂度分析
时间 O(n),额外空间 O(1)。
易错点
用额外排序会改变非零顺序,也不满足原地要求。
参考代码
Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。
class Solution:
def moveZeroes(self, nums):
write = 0
for read in range(len(nums)):
if nums[read] != 0:
nums[write], nums[read] = nums[read], nums[write]
write += 1class Solution {
public void moveZeroes(int[] nums) {
int write = 0;
for (int read = 0; read < nums.length; read++) {
if (nums[read] != 0) {
int t = nums[write]; nums[write] = nums[read]; nums[read] = t;
write++;
}
}
}
}class Solution {
public:
void moveZeroes(vector<int>& nums) {
int write = 0;
for (int read = 0; read < (int)nums.size(); read++) {
if (nums[read] != 0) {
swap(nums[write], nums[read]);
write++;
}
}
}
};func moveZeroes(nums []int) {
write := 0
for read := 0; read < len(nums); read++ {
if nums[read] != 0 {
nums[write], nums[read] = nums[read], nums[write]
write++
}
}
}var moveZeroes = function(nums) {
let write = 0;
for (let read = 0; read < nums.length; read++) {
if (nums[read] !== 0) {
[nums[write], nums[read]] = [nums[read], nums[write]];
write++;
}
}
};function moveZeroes(nums: number[]): void {
let write = 0;
for (let read = 0; read < nums.length; read++) {
if (nums[read] !== 0) {
[nums[write], nums[read]] = [nums[read], nums[write]];
write++;
}
}
}其他解法
覆盖后补零分两步:先压缩非零元素,再填零;双指针交换在一遍扫描中把非零元素换到前面,零自然被挤到后面,写操作只发生在非零元素上。
解法 2:覆盖后补零 时间 O(n),空间 O(1)
第一遍用写指针 k 把所有非零元素按顺序覆盖到数组前部;第二遍把下标 k 到末尾全部置为 0。
没有交换,逻辑最直白。零很少时仍要把尾部重写一遍;元素是复杂对象时不能简单地“补零”,交换法更通用。
class Solution:
def moveZeroes(self, nums):
k = 0
for x in nums:
if x != 0:
nums[k] = x
k += 1
for i in range(k, len(nums)):
nums[i] = 0class Solution {
public void moveZeroes(int[] nums) {
int k = 0;
for (int x : nums)
if (x != 0) nums[k++] = x;
for (int i = k; i < nums.length; i++) nums[i] = 0;
}
}class Solution {
public:
void moveZeroes(vector<int>& nums) {
int k = 0;
for (int x : nums)
if (x != 0) nums[k++] = x;
for (int i = k; i < (int)nums.size(); i++) nums[i] = 0;
}
};func moveZeroes(nums []int) {
k := 0
for _, x := range nums {
if x != 0 {
nums[k] = x
k++
}
}
for i := k; i < len(nums); i++ {
nums[i] = 0
}
}var moveZeroes = function(nums) {
let k = 0;
for (const x of nums)
if (x !== 0) nums[k++] = x;
for (let i = k; i < nums.length; i++) nums[i] = 0;
};function moveZeroes(nums: number[]): void {
let k = 0;
for (const x of nums)
if (x !== 0) nums[k++] = x;
for (let i = k; i < nums.length; i++) nums[i] = 0;
}