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

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

双指针算法解决数组原地修改问题。移动零通过读写指针将非零元素前移;复写零需先统计有效长度再反向遍历填充,避免覆盖未处理元素。两题均强调空间复杂度 O(1) 要求。

DevStack发布于 2026/3/28更新于 2026/10/2584 浏览
双指针算法实战:移动零与复写零

在学习了基础语法后,是时候通过实战题目来巩固双指针技巧了。今天重点讲解两道经典的数组原地修改问题:移动零与复写零。

一、移动零

题目描述

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

思路解析

最直观的想法是创建一个新数组,但题目限制了空间复杂度。我们可以利用双指针来解决:

  • 读指针 (read):遍历整个数组,寻找非零元素。
  • 写指针 (write):指向当前应该放置非零元素的位置。

当 read 遇到非零数时,将其与 write 位置的元素交换(如果两者不同),然后 write 前移。这样能保证所有非零元素按顺序被'挤'到前面,剩余的尾部自然填充为 0。

代码实现

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

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

二、复写零

题目描述

在一个固定长度的整数数组中,将每个出现的 0 复写一遍,导致后续元素向右移动,超出原数组长度的元素将被丢弃。同样需要原地修改。

思路解析

如果从前向后遍历并插入 0,会覆盖掉尚未处理的非零元素,因此不可行。正确的策略是从后向前处理:

  1. 统计有效长度:先遍历一次数组,模拟复写过程,计算出在复写后的逻辑数组中,最后一个会被保留的元素位置(记为 dest)。
  2. 边界判断:如果某个 0 被复写后超出了数组边界,说明这个 0 只能写入一次(即数组的最后一个位置)。
  3. :从计算出的位置开始,倒序遍历原数组,将元素写入目标位置。遇到 则写入两次(需检查边界)。
反向填充
0

代码实现

void duplicateZeros(int* arr, int arrSize) {
    int i = 0;
    int dest = -1;
    
    // 第一步:找出最后一个会被复写的元素位置
    while (i < arrSize) {
        if (arr[i]) {
            dest++;
        } else {
            dest += 2;
        }
        if (dest >= arrSize - 1) break;
        i++;
    }
    
    // 第二步:处理边界情况,如果最后一个元素是 0 且刚好溢出
    if (dest == arrSize) {
        arr[arrSize - 1] = 0;
        i--;
        dest -= 2;
    }
    
    // 第三步:从后向前进行复写
    while (i >= 0) {
        if (arr[i] == 0) {
            arr[dest--] = 0;
            if (dest >= 0) arr[dest--] = 0;
        } else {
            arr[dest--] = arr[i];
        }
        i--;
    }
}

这两道题的核心都在于理解双指针在不同场景下的配合方式。移动零侧重于'跳过无效数据',而复写零则考验对数组边界和覆盖逻辑的逆向思考。在实际开发中,类似的场景往往需要权衡时间复杂度与空间限制,掌握这种原地修改的技巧能显著提升代码效率。

目录

  1. 一、移动零
  2. 题目描述
  3. 思路解析
  4. 代码实现
  5. 二、复写零
  6. 题目描述
  7. 思路解析
  8. 代码实现

更多推荐文章

查看全部
  • XGBoost Python 详细教程与实战案例
  • 大模型幻觉问题治理:技术体系与工程实践
  • LLM 核心架构:程序员大语言模型技术指南
  • GitHub Copilot 学生身份认证与免费开通指南
  • 华为 OD 机试:员工派遣
  • Git 基础入门:从安装到核心操作
  • 从零构建高可用系统:端到端架构实战解析与避坑指南
  • kkFileView 如何选择最佳 JDK 版本及部署策略
  • 数据结构核心:链表详解与实现
  • VSCode 集成 GitHub Copilot 使用指南
  • Java 剪辑接单报价比价系统架构设计与实现
  • WebView 并发初始化竞争风险分析
  • 基于 AI 代码助手的开发板垃圾图片识别系统实战
  • 基于 DeepSeek 与通义万相的 AI 视频制作实战指南
  • LangChain 与 LlamaIndex 大模型应用开发工具对比分析
  • React JSX 基础:组件与 HTML 元素区分原则
  • OpenClaw 多飞书机器人配置指南
  • Flutter 底部导航与 TabBar 多页切换实战及鸿蒙适配
  • Flutter 组件 genkit 适配鸿蒙:模型幻觉审计与 RAG 向量对齐
  • Windows VSCode 配置 MinGW 与手动编译安装 OpenCV 实战

相关免费在线工具

  • 加密/解密文本

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

  • Gemini 图片去水印

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