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

双指针算法实战:移动零与复写零详解

双指针技巧解决数组原地操作问题。移动零通过交换非零元素至前端实现;复写零需从后向前遍历避免覆盖未处理数据。提供 C 语言完整代码示例及逻辑解析,涵盖边界条件处理与时间复杂度分析。

颠三倒四发布于 2026/3/280 浏览
双指针算法实战:移动零与复写零详解

双指针算法实战:移动零与复写零详解

基础打牢后,实战演练必不可少。今天用两道经典题目巩固双指针思想,重点在于原地操作和边界处理。

一、移动零

题目描述

给定一个数组 nums,将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。要求必须在原数组上操作,尽量减少总操作次数。

思路解析

这道题的核心是快慢指针。我们需要遍历数组,将非零元素依次移到前面,最后将剩余位置填充为 0。

具体做法如下:

  1. 定义两个指针,current 用于遍历整个数组,write 指向下一个非零元素应该放置的位置。
  2. 当 current 遇到非零元素时,将其与 write 位置的元素交换(如果两者不重合),然后 write 向前移动。
  3. 无论是否交换,current 都继续向后移动。
  4. 遍历结束后,write 之后的所有位置自然就是 0(或者在交换过程中已经归位)。

注意:这里不需要显式地填充 0,因为交换逻辑保证了非零元素前移,剩下的位置逻辑上即为空,但在实际代码中,为了严谨,通常会在遍历完非零元素后,将 write 到末尾的部分置为 0,或者利用交换特性直接完成。下面的代码采用交换法,逻辑更直观。

代码实现

void Swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

void moveZeroes(int* nums, int numsSize) {
    int write = 0;
    for (int current = 0; current < numsSize; current++) {
        if (nums[current] != 0) {
            // 只有当两个指针不重合时才需要交换,避免不必要的操作
            if (write != current) {
                Swap(&nums[write], &nums[current]);
            }
            write++;
        }
    }
}

这段代码提交后能顺利通过,关键在于理解 write 指针始终指向当前待填充的非零位置。

二、复写零

题目描述

在一个固定的整数数组中,将每个出现的 0 复制一遍,并将后续元素向右移动。数组长度固定,超出部分将被截断。

思路解析

如果从前往后遍历,遇到 0 就插入,会覆盖掉后面的元素,导致数据丢失。因此,必须从后往前进行复写。

步骤如下:

  1. 统计扩展后的长度:先遍历一次数组,计算如果所有 0 都被复写,最终需要的索引位置 dest。这决定了我们从哪里开始写入。
  2. 处理边界情况:如果最后一个被复写的元素超出了数组范围(即原数组末尾是 0 且会被截断),需要特殊处理,将最后一个元素设为 0。
  3. 从后向前写入:根据第一步确定的 dest 和当前的 cur,从数组末尾开始向前复制。如果是 0,则写入两次;否则写入一次。

代码实现

void duplicateZeros(int* arr, int arrSize) {
    int cur = 0;
    int dest = -1;
    
    // 第一步:找出最后一个元素在原数组中的位置
    while (cur < arrSize) {
        if (arr[cur]) {
            dest++;
        } else {
            dest += 2;
        }
        if (dest >= arrSize - 1) break;
        cur++;
    }
    
    // 第二步:判断边界情况,如果最后一个元素是 0 且刚好溢出
    if (dest == arrSize) {
        arr[arrSize - 1] = 0;
        cur--;
        dest -= 2;
    }
    
    // 第三步:从后向前实现复写操作
    while (cur >= 0) {
        if (arr[cur] == 0) {
            arr[dest--] = 0;
            arr[dest--] = 0;
        } else {
            arr[dest--] = arr[cur];
        }
        cur--;
    }
}

这个方案避免了频繁的数据移动,时间复杂度为 O(n),空间复杂度为 O(1),是处理此类问题的标准解法。

目录

  1. 双指针算法实战:移动零与复写零详解
  2. 一、移动零
  3. 题目描述
  4. 思路解析
  5. 代码实现
  6. 二、复写零
  7. 题目描述
  8. 思路解析
  9. 代码实现
  • 💰 8折买阿里云服务器限时8折了解详情
  • 💰 8折买阿里云服务器限时8折购买
  • 🦞 5分钟部署阿里云小龙虾了解详情
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

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

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

更多推荐文章

查看全部
  • OpenClaw 开源 AI 智能体框架技术解析与部署实践
  • OpenClaw 部署指南:Minimax/DeepSeek 模型与飞书机器人集成
  • C++ 多态详解:从实现条件到底层原理
  • 位运算算法实战:6 道经典题目详解(字符唯一性、缺失数字等)
  • NC221681 dd 爱框框:滑动窗口算法实战
  • KingbaseES 内核级 SQL 防火墙:白名单机制与零误报实践
  • PowerShell Invoke-WebRequest 报错 Invalid URL 和 CommandNotFound 排查指南
  • 无人机视角山区泥石流与滑坡图像识别数据集
  • 无人机航测正射影像制作:ContextCapture 与 Pix4D 实战指南
  • RTD1296PB 与 RK3568:NAS 与智能家居芯片实战对比
  • 位运算算法实战:字符唯一性、丢失数字与消失数字
  • Python 基础语法完全指南:变量、数据类型与运算符
  • 前端 JS 加载失败怎么办?重试与多源备份方案
  • OpenClaw 开源 AI 智能体框架:技术架构、部署与安全分析
  • 前端地图开发基础:服务类型、坐标系与 SDK 简介
  • OpenClaw 部署指南:集成 Minimax/DeepSeek 模型与飞书机器人
  • C++ 入门进阶:输入输出、缺省参数与函数重载
  • OpenClaw 部署指南:模型接入与飞书机器人配置
  • 秋叶绘世 Stable Diffusion 整合包技术解析与使用指南
  • GitHub Copilot Agent Skills 实战:打造跨项目 AI 专属工具箱

相关免费在线工具

  • 加密/解密文本

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

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online