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

双指针算法专题:移动零、复写零与快乐数

介绍双指针算法的两种常见形式:对撞指针与快慢指针。通过对撞指针解决移动零、复写零及盛水最多容器问题,强调原地操作与单调性优化;通过快慢指针解决快乐数问题,利用循环检测判断是否快乐。文章包含详细思路解析、可视化演示及 C++ 代码实现,涵盖 LeetCode 经典例题。

PhpPioneer发布于 2026/3/30更新于 2026/5/2426 浏览
双指针算法专题:移动零、复写零与快乐数

引言

常见的双指针有两种形式,一种是对撞指针,一种是快慢指针。

对撞指针:一般用于顺序结构中,也称左右指针。从两端向中间移动。终止条件一般是两个指针相遇或者错开(left == right 或 left > right)。 快慢指针:又称为龟兔赛跑算法,基本思想是使用两个移动速度不同的指针在数组或链表等序列结构上移动。常用于处理循环往复的情况。 ***注意:***这里的指针并不是 C 语言中的地址指针,而是用变量记录数组下标。

283. 移动零

题目描述

文章配图

实现核心及思路

解题思路: 对撞指针方案行不通,因为题目要求移动 0 元素的同时还要保证非零元素的相对顺序。采用两个指针都从数组的左端出发,把非零的元素依次找到放在前面,最后剩下 0 自然就排在数组后面了。

  1. 刚开始让一个指针 cur 先指向数组的第一个元素,另一个指针 dest 初始化为 -1。cur 用来找非零元素,dest 用来确定 cur 之前的 0 元素。
  2. 当 cur 指向的元素为零则 cur++,继续向后找非零元素来将前面的 0 交换到后面;
  3. 当 cur 指向的元素不为 0,则让 dest 向前移动一位(dest++),然后交换 cur 和 dest 指向的元素,cur 继续向后移动(cur++)。
  4. 结束条件:当 cur 走到数组尾部的时候意味着所有非零元素都找到了,结束。

思路可视化: 文章配图 文章配图

代码实现:

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int size = nums.size();
        int dest = -1;
        int cur = 0;
        while(cur < size) {
            if(nums[cur] != 0) {
                dest++;
                swap(nums[dest], nums[cur]);
            }
            cur++;
        }
    }
};

代码测试:

int main() {
    Solution s;
    vector<int> v1{ 1,0,2,0,3,0,4 };
    vector<int> v2{ 0,0,0,6,5,4 };
    s.moveZeroes(v1);
    for (auto e : v1) { cout << e << " "; }
    cout << endl;
    s.moveZeroes(v2);
    for (auto e : v2) { cout << e << " "; }
    return 0;
}

文章配图

1089. 复写零

题目描述

文章配图

实现核心及思路

解题思路: **解法一:**额外创建一个等大的数组,遍历原数组,遇到 0 写入两次。但题目限制在原数组操作。 **解法二:**观察示例可知,最终输出结果会覆盖原有数据。考虑从后往前遍历数组来复写零。问题转化为:先找最后一个有效元素,然后从该位置开始从后往前遍历复写零。 **步骤一:**利用双指针法找最后一个有效元素位置。cur 指针开始指向第一个元素,定义 dest 指针(初始化为 -1)。当 cur 指向非零元素,dest 向后移动一位;当 cur 指向零元素,dest 向后移动两位。结束条件:dest < size - 1。

***细节一:***当进入循环后发现 dest 移动两次后到了数组的末尾,此时不能再让 cur 向前移动了,否则数组空间不够。 **步骤二:**继续利用双指针法,cur 指向最后一个有效数据,dest 指向数组的最后。从 cur 开始向前遍历。非零元素写一次,0 元素写两次。结束条件:cur >= 0。 ***细节二:***当 cur 指向最后一个有效数据且为 0 时,dest 需要向后移动两次,但数组空间只剩一个位置。意味着这个 0 只能复写一次,需单独处理。

思路可视化: 文章配图

代码实现:

class Solution {
public:
    void duplicateZeros(vector<int>& arr) {
        int cur = 0;
        int dest = -1;
        int size = arr.size();
        while (dest < size - 1) {
            if (arr[cur] == 0) dest += 2;
            else dest++;
            if (dest < size - 1) cur++;
        }
        if (dest >= size) {
            arr[size - 1] = 0;
            dest = size - 2;
            cur--;
        }
        while (cur >= 0) {
            if (arr[cur] == 0) {
                arr[dest--] = 0;
                arr[dest--] = 0;
            } else arr[dest--] = arr[cur];
            cur--;
        }
    }
};

代码测试:

int main() {
    Solution s;
    vector<int> v1{ 1, 0, 2, 3, 0, 4, 5, 0 };
    vector<int> v2{ 1, 0, 2, 3, 0, 4, 5 };
    vector<int> v3{ 1, 0, 2, 3, 0, 4 };
    s.duplicateZeros(v1);
    s.duplicateZeros(v2);
    s.duplicateZeros(v3);
    for (auto e : v1) cout << e << " "; cout << endl;
    for (auto e : v2) cout << e << " "; cout << endl;
    for (auto e : v3) cout << e << " ";
    return 0;
}

文章配图

202. 快乐数

题目描述

文章配图

实现核心及思路

解题思路: 对于 n = 19,经过求和后结果为 1,即为快乐数;n = 2,经过求和又回到了起点。 结论:对于每个非零整数,进行上面的操作,要么最终得到 1,要么进入一个循环。对于这种循环的问题,均可以用快慢指针的方法解决。 假设慢指针一次走一步,快指针一次走两步,那么快指针一定先入环,但由于两者的速度差,最终肯定会相遇。 对于这个题而言:慢指针走一步即对应一次求和,快指针走两步即对应连续求和两次。 结束条件:当快慢指针相遇。如果相遇时,快慢指针指向的和为 1,这个数即为快乐数;反之,则不是。

代码实现:

class Solution {
public:
    int Sum(int n) {
        int sum = 0;
        while(n) {
            int a = n%10;
            sum += pow(a,2);
            n/=10;
        }
        return sum;
    }
    bool isHappy(int n) {
        int slow = Sum(n);
        int fast = Sum(n);
        fast = Sum(fast);
        while(slow != fast) {
            slow = Sum(slow);
            fast = Sum(fast);
            fast = Sum(fast);
        }
        if(slow == 1) return true;
        else return false;
    }
};

11. 盛水最多容器

题目描述

文章配图 文章配图

实现核心及思路

解题思路: **解法一:**暴力解法,两次 for 循环,算出所有的体积,找出最大值。 解法二:对撞指针(左右指针),left 和 right 指针向右向左找符合的桶。依靠单调性,当 left 和 right 向内移动时,宽度一定是变短的,体积 V = 宽度 * 高,所以要想找到最大的体积,只能依靠找到更大的高度。 让 left 和 right 中指向高度较小的一个向内移动,找更大的高度,才有可能使体积更大。同时,每次计算一个体积,通过比较获得最大体积。

💡库当中有一个 max 函数可以帮我们找两个数中的较大值,头文件

思路可视化: 文章配图

代码实现:

class Solution {
public:
    int maxArea(vector<int>& height) {
        int left = 0;
        int right = height.size() - 1;
        int m = 0;
        while(left < right) {
            int h = height[left] > height[right] ? height[right] : height[left];
            int V = (right - left) * h;
            m = max(m,V);
            if(height[left] < height[right]) left++;
            else right--;
        }
        return m;
    }
};

文章配图 文章配图

目录

  1. 引言
  2. 283. 移动零
  3. 题目描述
  4. 实现核心及思路
  5. 1089. 复写零
  6. 题目描述
  7. 实现核心及思路
  8. 202. 快乐数
  9. 题目描述
  10. 实现核心及思路
  11. 11. 盛水最多容器
  12. 题目描述
  13. 实现核心及思路
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

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

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

更多推荐文章

查看全部
  • Xilinx FPGA 管脚与时序约束实战指南
  • 无线联邦学习:隐私保护下的 AI 协同进化
  • 基于开源飞控 Pixhawk 的无人机装调与测试
  • 聊聊数据异构与多级缓存同步方案
  • 使用 C# 扩展 Dynamics 365 Copilot:自定义插件与场景
  • C++ 基础教程:从 Hello World 到变量类型
  • ClawX 可视化 AI 智能体使用指南
  • 91n 边缘设备部署轻量 TensorFlow 模型全流程
  • Docker exited 容器自动清理与资源管理实战
  • 数据结构核心:二叉树概念、性质与堆的实现
  • 智能家居电平转换电路实战:从理论到PCB制作
  • 上海交通大学提出大模型人类可读指纹技术,有效识别模型盗用与滥用
  • Python 如何在运行时调用其他文件中的函数
  • Python 临床知识问答与检索系统架构设计与实现
  • C++ 回文自动机(PAM):原理、实现与应用
  • 大模型 LLM 学习路线图全面解析与核心技能指南
  • MetaRTC 跨平台 WebRTC SDK 开发入门指南
  • Claude Code Viewer: Web 端会话管理工具
  • 融合选择性卷积与残差结构的 SKResNet 架构详解
  • Python 函数、列表与元组核心用法及实战案例

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如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