跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava算法

LeetCode 原地复写零:双指针 + 逆向填充实现 O(n) 时间 O(1) 空间

LeetCode 原地复写零问题要求在固定长度数组中复写 0 并右移元素。为避免正向遍历导致的数据覆盖,采用双指针配合逆向填充策略。先扫描确定逻辑边界,再倒序修改数组。该方案无需额外空间,时间复杂度 O(n),空间复杂度 O(1),是解决此类原地修改问题的经典高效解法。

黑客发布于 2026/3/27更新于 2026/7/2033 浏览
LeetCode 原地复写零:双指针 + 逆向填充实现 O(n) 时间 O(1) 空间

LeetCode 原地复写零:双指针 + 逆向填充实现 O(n) 时间 O(1) 空间

这道题要求我们在固定长度的数组中复写每个 0,并将后面的元素向右移动。最直接的思路是遇到 0 就插入并右移,但这样会导致 O(n^2) 的时间复杂度,且容易越界。既然题目限制原地修改且不使用额外数组,我们需要一种更聪明的方法。

核心思路:逆向填充

如果从前向后遍历,新写入的 0 会覆盖掉原本需要保留的数据。为了避免这个问题,我们可以先计算一下'逻辑上'数组扩展后的长度,找到最后一个需要被写入的位置,然后从后往前进行填充。

第一步:确定边界

我们使用两个指针:cur 用于遍历原数组,pre 模拟复写后的数组索引。

  • 当 arr[cur] 不为 0 时,pre 只前进一位。
  • 当 arr[cur] 为 0 时,pre 前进两位(因为 0 会被复写)。
  • 一旦 pre 超过或等于数组长度 n,说明我们已经确定了复写的边界,停止扫描。

这里有个特殊情况:如果 pre 刚好等于 n,说明最后一个元素是 0,它只需要占据一个位置(因为数组长度固定),此时需要将数组末尾的元素设为 0,并调整指针回退。

第二步:从后向前填充

确定好边界后,让 cur 和 pre 都指向各自的有效终点,开始倒序遍历:

  • 如果当前元素不是 0,直接复制到 pre 位置。
  • 如果是 0,则连续复制两次 0 到 pre 和 pre-1 位置。
  • 每次操作后,指针向前移动。

这种方法既避免了数据覆盖,又保证了只遍历两次数组,效率极高。

代码实现

class Solution {
    public void duplicateZeros(int[] arr) {
        int cur = 0, pre = -1, n = arr.length;
        
        // 1. 找到要复写的最后一个元素
        while (cur < n) {
            if (arr[cur] == 0) {
                pre += 2;
            } else {
                pre++;
            }
            if (pre >= n - 1) {
                break;
            }
            cur++;
        }
        
        // 2. 处理边界情况:如果最后一个元素是 0 且刚好占满
        if (pre == n) {
            arr[n - 1] = 0;
            cur--;
            pre -= 2;
        }
        
        // 3. 从后向前复写
        while (cur >= 0) {
            if (arr[cur] != 0) {
                arr[pre--] = arr[cur--];
            } else {
                arr[pre--] = 0;
                arr[pre--] = 0;
                cur--;
            }
        }
    }
}

复杂度分析

  • 时间复杂度:O(n)。我们最多遍历数组两次,一次用于定位边界,一次用于填充。
  • 空间复杂度:O(1)。完全在原数组上操作,没有申请额外的存储空间。

这种'先定界、后回填'的思路在处理数组原地修改问题时非常通用,值得记住。

目录

  1. LeetCode 原地复写零:双指针 + 逆向填充实现 O(n) 时间 O(1) 空间
  2. 核心思路:逆向填充
  3. 第一步:确定边界
  4. 第二步:从后向前填充
  5. 代码实现
  6. 复杂度分析
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • C++ 类与对象进阶特性与编译器优化实战
  • 图寻路算法详解:基于深度优先搜索 (DFS) 的 Java 实现
  • Android Framework 核心源码解析:进程通信与系统服务详解
  • LangChain 框架入门:核心组件、模块与文档指南
  • C++ 高并发内存池实战:ThreadCache 设计与实现
  • 利用 Frontend-Design Skill 提升大模型前端设计能力
  • 命令行 MCP 客户端实践:MCPHost 使用与模型兼容性测试
  • Python 工程师常见基础面试题
  • AIGC 个性化与定制化内容生成技术与应用
  • Linux 文件描述符与重定向实战:从原理到 minishell 实现
  • Graphite Whisper 配置:Carbon 发送间隔与归档策略 AI 建议
  • C/C++ 输入输出实战:OJ 场景与性能优化
  • 一切皆是映射:深入理解 DQN 的稳定性与收敛性
  • Python 异步编程与协程实战指南
  • 两数之和:暴力枚举与哈希表优化
  • 快速创建适配 imToken DApp 浏览器的区块链小游戏应用
  • LangChain 结合 Milvus 与千帆大模型构建 RAG 应用实践
  • OpenClaw 本地部署指南:快速搭建自托管 AI 管家
  • C#多级缓存架构设计与实现
  • GitHub Copilot 使用体验与优缺点分析

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online