283. Move Zeroes

練習日期:2026-01-06

難度:Easy

類型:Array、Two Pointers

📘 題目敘述

給定一個整數陣列 nums,請將所有的 0 移動到陣列的最後方,同時維持非零元素的相對順序

注意:

  • 必須在不複製陣列的情況下就地(in-place)完成操作。

條件限制

  • 1 ≤ nums.length ≤ 10^4
  • -2^31 ≤ nums[i] ≤ 2^31 - 1

🧠 解題思路(一)(直覺想法)

我的想法是把這題拆成兩個非常直觀的步驟來處理:

  1. 先把所有非 0 的數字依照原本順序收集起來
  2. 再把出現過的 0 全部接在後面

這樣可以很清楚地確保:

  • 非零元素的相對順序不會被改變
  • 所有的 0 都會集中在陣列最後

所有變數(對應程式碼)

  • n:原始陣列 nums 的長度
  • zeros:紀錄陣列中 0 出現的次數
  • ans:暫時存放「非零元素 + 最後補 0」的新陣列

🪜 主要流程步驟

步驟一:掃描整個陣列,分離 0 與非 0

for (int i = 0; i < n; i++) {
    if (nums[i] == 0) {
        zeros++;
    } else {
        ans.push_back(nums[i]);
    }
}

這個迴圈做的事情是:

  • 如果遇到 0,就只記錄次數(zeros++
  • 如果不是 0,就依照原本順序放進 ans

結束後:

  • ans 裡面只會有所有非零元素(順序不變)
  • zeros 則記錄了後面需要補幾個 0

步驟二:把所有的 0 接到後面

for (int j = 0; j < zeros; j++) {
    ans.push_back(0);
}

根據剛剛記錄的 zeros 次數,將對應數量的 0 接到 ans 的尾端。

這一步完成後,ans 就已經符合題目要求的排列結果。


步驟三:更新原陣列

nums = ans;

將整理好的結果直接指定回 nums,等同於完成「把所有 0 移到最後」的操作。


為什麼這樣做是正確的?

題目要求非零元素的相對順序不能改變,我的做法是「先照順序收集非零,再補 0」,不需要交換、不會打亂順序。

💻 程式碼實作

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int n = nums.size();
        int zeros = 0;
        vector<int> ans;
        for (int i = 0; i < n; i++) {
            if (nums[i] == 0) {
                zeros++;
            } else {
                ans.push_back(nums[i]);
            }
        }
        for (int j = 0; j < zeros; j++) {
            ans.push_back(0);
        }
        nums = ans;
    }
};

🧠 解題思路(二)(Two Pointers 原地優化)

在原本的解法中,我使用了一個額外的陣列來存放結果,雖然邏輯清楚,但需要額外的 O(n) 空間。

後來我將作法改成 Two Pointers 的原地處理方式,在不使用額外陣列的情況下,直接在 nums 本身完成操作。

新增指標 pos:記錄下一個非 0 要放的位置

  • pos 表示目前應該放「下一個非 0 元素」的索引位置
  • 一開始設為 0,代表從陣列最前面開始放

第一階段:把所有非 0 元素往前搬

for (int i = 0; i < n; i++) {
    if (nums[i] != 0) {
        nums[pos] = nums[i];
        pos++;
    }
}

這個迴圈的邏輯是:

  • i 從左到右掃描整個陣列
  • 只要遇到非 0 的數字,就把它放到 nums[pos],然後 pos++

這樣可以保證:

  • 所有非 0 元素會依照原本順序集中在陣列前半段
  • pos 最後停在「非 0 區段的結尾」

第二階段:把後面的空位全部補成 0

while (pos < nums.size()) {
    nums[pos] = 0;
    pos++;
}

前半段已經放好所有非 0 元素,剩下的位置一定都應該是 0,直接補 0 到陣列結尾即可。


為什麼這樣改比較好?

  • 不需要額外的陣列(空間複雜度從 O(n)O(1)
  • 非 0 元素的相對順序完全不會被破壞
  • 邏輯仍然是「先處理非 0,再補 0」,和原本想法一致

💻 程式碼實作

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int n = nums.size();
        int pos = 0;
        for (int i = 0; i < n; i++) {
            if (nums[i] != 0) {
                nums[pos] = nums[i];
                pos++;
            }
        }
        while (pos < nums.size()) {
            nums[pos] = 0;
            pos++;
        }
    }
};

https://leetcode.com/problems/move-zeroes/

作者: scottnick
撰寫日期: 2026-01-06
類別:
原文連結: https://scottnick.github.io/cpp-notes/all%20problems/283-move-zeroes.html