跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
搜索
|注册
博客列表
Javajava算法

LeetCode 原地复写零:双指针与逆向填充的 O(n) 解法

综述由AI生成针对数组中复写零并右移元素的题目,核心难点在于原地修改避免覆盖。通过双指针先确定扩展后的边界,再逆向填充数据,可确保 O(n) 时间复杂度且仅使用 O(1) 额外空间。该方法有效解决了正向遍历导致的元素丢失问题,是处理此类数组操作的高效策略。

蓝绿部署发布于 2026/3/29更新于 2026/4/252 浏览
LeetCode 原地复写零:双指针与逆向填充的 O(n) 解法

算法演示图

本文聚焦 LeetCode'原地复写零'经典题目,核心需求是在固定长度数组中复写每个 0 并右移其余元素,且需满足原地修改、不使用额外数组空间的约束。正向遍历易导致后续元素被覆盖,为此详解双指针 + 逆向填充的优雅解法。

一、问题描述

给定一个固定长度的整数数组 arr,将数组中出现的每个 0 都复写一遍,并将其余元素向右平移。注意:不能在超出原数组长度的地方写入元素,且必须原地修改输入数组,不能使用额外的空间。

示例图

二、思路分析

这道题最直观的想法是遇到 0 就插入,但这样会导致后面的元素不断移动,效率低下甚至无法在 O(1) 空间内完成。关键在于:如果从前往后处理,新写入的 0 会覆盖掉原本需要保留的数据。

因此,我们需要先确定最终数组的边界在哪里,然后从后往前进行填充。这样可以保证我们不会覆盖掉还未处理的元素。

1. 确定复写边界

定义两个指针:

  • cur:遍历原数组的指针。
  • pre:模拟复写后数组的指针(指向逻辑上的末尾)。

遍历规则如下:

  • 当 arr[cur] == 0 时,pre 向后移动两位(因为 0 会被复写两次)。
  • 当 arr[cur] != 0 时,pre 向后移动一位。

当 pre >= n - 1 时,说明已经触及或超过了数组边界,此时 cur 指向的就是最后一个需要处理的元素。

这里有一个特殊的边界情况:如果 pre 恰好等于 n,说明最后一个要复写的元素是 0,且它占据了数组的最后一位。这种情况下,我们需要单独处理,将数组最后一位设为 0,并将 cur 向前回退一位。

边界情况示意图

2. 逆向填充

确定了边界后,从 cur 开始向前遍历:

  • 如果当前元素不为 0,直接将其复制到 pre 位置,然后双指针同时前移。
  • 如果当前元素为 0,则需要在 pre 和 pre-1 位置都填入 0,然后双指针前移。

逆向填充示意图

三、代码实现

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++;
        }
        
        // 处理边界情况:如果 pre == n,说明最后一个元素是 0 且刚好占满最后一位
        if (pre == n) {
            arr[n - 1] = 0;
            cur--;
            pre -= 2;
        }
        
        // 2. 开始从后向前复写
        while (cur >= 0) {
            if (arr[cur] != 0) {
                arr[pre--] = arr[cur--];
            } else {
                arr[pre--] = 0;
                arr[pre--] = 0;
                cur--;
            }
        }
    }
}

四、复杂度分析

  • 时间复杂度 O(n):只需要遍历数组两次,第一次定位边界,第二次逆向填充。
  • 空间复杂度 O(1):使用的原数组,没有额外分配空间。

五、总结

本解法通过双指针先定位复写边界,再逆向填充数组,既避免了正向遍历的元素覆盖问题,又实现了 O(n) 线性时间复杂度与 O(1) 常数空间复杂度的最优表现。其中'先确定边界、再逆向操作'的思路,是解决数组原地修改类问题的关键技巧,具有较强的通用性与实用性。

运行效果

目录

  1. 一、问题描述
  2. 二、思路分析
  3. 1. 确定复写边界
  4. 2. 逆向填充
  5. 三、代码实现
  6. 四、复杂度分析
  7. 五、总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • 💰 8折买阿里云服务器限时8折购买
  • 🦞 5分钟部署阿里云小龙虾了解详情
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

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

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

更多推荐文章

查看全部
  • C++七级GESP 核心知识点详解
  • MySQL 慢查询日志:配置、分析与性能优化实战
  • MinIO 分布式对象存储实战:部署、mc 命令与 SeaweedFS 对比
  • Spring Boot 结合 Leaflet 实现省级旅游口号 WebGIS 可视化
  • PyTorch 核心机制:自动微分与雅可比向量积详解
  • WebGL 基础教程:矩阵变换原理与 3D 动画实战
  • Go 语言 Ebiten 坦克大战实现
  • C++ 多态核心原理与实现
  • WPScan 漏洞扫描工具使用指南:安装、配置与实战
  • 数据结构与算法实战:查找算法核心原理与代码实现
  • libwebkit2gtk-4.1-0 安装依赖处理:Ubuntu 22.04 场景解析
  • Python、PyTorch、CUDA 及 MMCV/MMDetection 版本对应指南
  • 机器人技术中的李群与李代数基础理解
  • Java 后端实习复盘:企业级开发流程与核心模块解析
  • 中国机器人及人工智能大赛自主巡航实战经验分享
  • Python 类(Class)语法、技巧与实战案例
  • MiroFish:基于群体智能的万物预测引擎
  • 基于 Claude 处理超长文档的 Prompt 编写指南
  • Linux 多线程基础:线程与进程的关系及特性
  • 50 道经典 Python 面试题解析

相关免费在线工具

  • 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