LeetCode 283:原地移动零的优雅解法

LeetCode 热题 283. 移动零:原地操作的优雅解法

一、题目理解:需求很明确

题目要求:

  • 把数组里的所有0移到末尾
  • 保持非零元素的相对顺序
  • 必须原地操作(不能复制新数组)

比如输入[0,1,0,3,12],输出得是[1,3,12,0,0];如果输入本身就是[0],直接返回[0]就行。

二、我的解题思路:两步走策略

一开始我想的是「双指针交换」,但后来发现更简洁的是 **"先填非零,再补零"** 的思路:

解法核心逻辑

  1. 第一步:把非零元素 "往前搬" 用一个变量stack_size记录 "非零元素应该放的位置",遍历数组时,遇到非零元素就放到nums[stack_size],然后stack_size自增。(相当于把所有非零元素按顺序 "堆" 在数组前半部分)

  2. 第二步:给剩下的位置补 0 遍历结束后,从stack_size的位置开始,把数组剩下的部分全填成 0。

代码实现(C++)

cpp

复制代码
class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int stack_size = 0;
        // 第一步:填充非零元素
        for (int x : nums) {
            if (x) {
                nums[stack_size++] = x;
            }
        }
        // 第二步:补0
        fill(nums.begin() + stack_size, nums.end(), 0);
    }
};

三、为什么这个解法高效?

  • 时间复杂度 O (n):只遍历数组两次(一次填非零,一次补零),n 是数组长度。
  • 空间复杂度 O (1):完全原地操作,没额外开数组。
  • 操作次数少:比起 "遇到 0 就交换" 的写法,减少了不必要的交换操作(比如连续多个 0 的情况)。

四、拓展:双指针交换法(另一种思路)

其实也可以用双指针 实现(比如left指针指向 "下一个非零元素该放的位置"):

cpp

复制代码
void moveZeroes(vector<int>& nums) {
    int left = 0;
    for (int i = 0; i < nums.size(); i++) {
        if (nums[i] != 0) {
            swap(nums[left], nums[i]);
            left++;
        }
    }
}

这个写法更 "紧凑",但本质和 "填非零 + 补零" 是一个逻辑 ------ 只是把 "赋值" 换成了 "交换"~

相关推荐
Anastasiozzzz几秒前
Java Lambda 揭秘:从匿名内部类到底层原理的深度解析
java·开发语言
骇客野人2 分钟前
通过脚本推送Docker镜像
java·docker·容器
刘琦沛在进步4 分钟前
【C / C++】引用和函数重载的介绍
c语言·开发语言·c++
机器视觉的发动机16 分钟前
AI算力中心的能耗挑战与未来破局之路
开发语言·人工智能·自动化·视觉检测·机器视觉
铁蛋AI编程实战19 分钟前
通义千问 3.5 Turbo GGUF 量化版本地部署教程:4G 显存即可运行,数据永不泄露
java·人工智能·python
HyperAI超神经23 分钟前
在线教程|DeepSeek-OCR 2公式/表格解析同步改善,以低视觉token成本实现近4%的性能跃迁
开发语言·人工智能·深度学习·神经网络·机器学习·ocr·创业创新
晚霞的不甘30 分钟前
CANN 编译器深度解析:UB、L1 与 Global Memory 的协同调度机制
java·后端·spring·架构·音视频
SunnyDays101132 分钟前
使用 Java 冻结 Excel 行和列:完整指南
java·冻结excel行和列
R_.L33 分钟前
【QT】常用控件(按钮类控件、显示类控件、输入类控件、多元素控件、容器类控件、布局管理器)
开发语言·qt
Zach_yuan42 分钟前
自定义协议:实现网络计算器
linux·服务器·开发语言·网络