在问 · 算法题解

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 += 1

载入编辑器,自己跑一遍 →

其他解法

覆盖后补零分两步:先压缩非零元素,再填零;双指针交换在一遍扫描中把非零元素换到前面,零自然被挤到后面,写操作只发生在非零元素上。

解法 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] = 0

双指针 专题的其他题目

查看 双指针 全部题目 →