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

双指针算法技巧全场景拆解:从数组操作到环检测

双指针算法是解决数组类问题的常用技巧,通过两个下标协同移动优化遍历效率。移动零、复写零、快乐数、盛最多水的容器、有效三角形个数、两数之和及三数之和等经典例题。涵盖快慢指针、左右指针等多种模式,重点讲解边界处理、去重逻辑及时间复杂度优化至 O(n) 的实现方法。提供完整 C++ 代码示例与关键步骤解析,帮助掌握双指针在区间求解、环检测及多指针协同中的应用。

城市逃兵发布于 2026/2/7更新于 2026/7/2344 浏览
双指针算法技巧全场景拆解:从数组操作到环检测

引言

在算法题中,双指针技巧是一类高频且实用的解题方法。它并非真正的'指针',而是通过两个数组下标(或迭代器)的协同移动,在数组划分、区间求解、环检测等场景中实现高效遍历与逻辑处理,往往能将时间复杂度从暴力法的 O(n^2) 优化至 O(n),是解决数组类难题的关键。

双指针概述

常用于:数组划分和数组分块

注意:这里的指针不是真的指针,是数组的下标

经典例题解析

移动零

题目链接: 283. 移动零

思路:

  • cur:从左往右遍历数组
  • dest:已处理区间内,非零元素的最后一个位置

双指针示意图

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

复写零

题目链接: 1089. 复写零

思路:

  1. 先找到最后一个被复写的数。判断 cur 位置的值,cur 放到下标 0 位置,dest 放到下标 -1 位置。
  2. 如果 dest 超过最后那个数的位置,需特殊处理。
  3. 从后向前完成复写操作。

注意:

  • vector 的 size()-1 就是最后一个位置的下标,区分元素和下标。
  • 区分 == 和 =。
  • size() 在用来表示下标的时候,建议赋值给 int 类型后再用,否则涉及无符号整数提升可能导致问题。
  • class Solution {
    public:
        void duplicateZeros(vector<int>& arr) {
            int cur = 0;
            int dest = -1;
            for (; dest < (int)arr.size() - 1; cur++) {
                if (arr[cur] == 0) dest++;
                dest++;
            }
            cur--;
            if (dest == arr.size()) {
                arr[arr.size() - 1] = 0;
                dest -= 2;
                cur--;
            }
            for (; cur >= 0; cur--) {
                arr[dest] = arr[cur];
                if (arr[cur] == 0) arr[--dest] = 0;
                dest--;
            }
        }
    };
    

    快乐数

    题目链接: 202. 快乐数

    思路: 结果只有两种可能:为 1 或者无限循环。对于无限循环的情况,可以使用快慢双指针去解决(类似链表判环)。快慢指针的起点都是 n,快慢指针一定会在环入口相遇。

    class Solution {
    public:
        int algorithm(int p) {
            int sum = 0;
            while (p >= 10) {
                int q = p % 10;
                p /= 10;
                sum += q * q;
            }
            sum += p * p;
            return sum;
        }
    
        bool isHappy(int n) {
            int slow = n;
            int fast = n;
            slow = algorithm(slow);
            fast = algorithm(algorithm(fast));
            while (slow != fast) {
                slow = algorithm(slow);
                fast = algorithm(algorithm(fast));
            }
            return slow == 1;
        }
    };
    

    盛最多水的容器

    题目链接: 11. 盛最多水的容器

    思路:

    • left 放在最左边,right 放在最右边。
    • 比较之后,看 left 和 right 哪个对应的值小些,就把哪个向另外一边靠近。
    class Solution {
    public:
        int maxArea(vector<int>& height) {
            int left = 0;
            int right = height.size() - 1;
            int max1 = 0;
            while (left != right) {
                max1 = max(max1, (right - left) * min(height[right], height[left]));
                if (height[left] < height[right]) left++;
                else right--;
            }
            return max1;
        }
    };
    

    有效三角形的个数

    题目链接: 611. 有效三角形的个数

    思路:

    • 相关数学知识:三角形最小的那两边之和 > 最大那一边就可以构成三角形了。
    • 方法:先给数组排序,然后先固定最大的数,在最大的数的左边用双指针算法去找符合的数;然后再缩小最大的数。
    • 注意:如果 nums[left] + nums[right] > nums[c],那么 right - left 就是第二大数下标为 right 时的总个数,然后 right--。
    class Solution {
    public:
        int triangleNumber(vector<int>& nums) {
            sort(nums.begin(), nums.end());
            int c = nums.size() - 1;
            int ret = 0;
            while (c >= 2) {
                int left = 0;
                int right = c - 1;
                while (left != right) {
                    if ((nums[left] + nums[right]) > nums[c]) {
                        ret += right - left;
                        right--;
                    } else {
                        left++;
                    }
                }
                c--;
            }
            return ret;
        }
    };
    

    查找总价格为目标值的两个商品

    题目链接: 两数之和 II - 输入有序数组

    思路:

    • 这个题有单调性,用双指针正好(或者二分算法),能用双指针肯定优先用双指针。
    • 注意:此题没说找不到怎么办,就不用管那种情况,但是力扣要求所有路径都要有返回值,在最后加个 return 即可。
    class Solution {
    public:
        vector<int> twoSum(vector<int>& price, int target) {
            vector<int> ret;
            int left = 0;
            int right = price.size() - 1;
            while (left != right) {
                if (price[left] + price[right] > target) right--;
                else if (price[left] + price[right] < target) left++;
                else {
                    ret.push_back(price[left]);
                    ret.push_back(price[right]);
                    break;
                }
            }
            return ret;
        }
    };
    

    三数之和

    题目链接: 三数之和

    思路:

    • 这种和怎么样怎么样的一般都排序之后用双指针。
    • 细节问题:
      1. 去重:left 和 right 以及固定的那个数都要跳过重复元素(哪个跟哪个比较 == 才去要注意),同时要避免越界,比如 left 一直要 < right。
      2. 不漏:找到一种结果之后,不能直接 break 出去,要继续寻找,例如 left++; right--;。
    class Solution {
    public:
        vector<vector<int>> threeSum(vector<int>& nums) {
            vector<vector<int>> ret;
            sort(nums.begin(), nums.end());
            int size = nums.size();
            for (int k = 0; k < size - 2; k++) {
                if (nums[k] > 0) break;
                if (k > 0 && nums[k] == nums[k - 1]) continue;
                int i = k + 1;
                int j = size - 1;
                while (i < j) {
                    int sum = nums[k] + nums[i] + nums[j];
                    if (sum > 0) j--;
                    else if (sum < 0) i++;
                    else {
                        ret.push_back({nums[k], nums[i], nums[j]});
                        i++;
                        j--;
                        while (i < j && nums[i] == nums[i - 1]) i++;
                        while (i < j && nums[j] == nums[j + 1]) j--;
                    }
                }
            }
            return ret;
        }
    };
    

    目录

    1. 引言
    2. 双指针概述
    3. 经典例题解析
    4. 移动零
    5. 复写零
    6. 快乐数
    7. 盛最多水的容器
    8. 有效三角形的个数
    9. 查找总价格为目标值的两个商品
    10. 三数之和
    • 免费图片AI生成工具免费生成了解详情
    • Magick API 一键接入全球大模型注册送1000万token查看
    • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
    • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
    • 100+免费在线小游戏爽一把
    极客日志微信公众号二维码

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

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

    更多推荐文章

    查看全部
    • Coze AI 智能体工作流从配置到使用实战详解
    • Stable Diffusion 绘图功能详解:局部重绘与换装应用
    • GPT Image 2 安全审查真相:不是只看“性感”,而是在预测你的意图
    • Java 高频面试题汇总与核心知识点解析
    • Visual Studio Code 跨平台安装与配置指南
    • C++ 核心概念与面试知识点梳理
    • cli21/cli 现代 C++ 命令行界面库使用指南
    • 谷歌如何识别AI生成图片及Midjourney版权标注规范
    • LLM 推理思维链变体:TOT、GOT、AOT、SoT 与 PoT 详解
    • DeepSeek-R1 技术解析:训练流程与架构设计详解
    • UI UX Pro Max:让 AI 辅助生成专业级前端 UI 代码
    • C++ 递归入门:汉诺塔问题的思路与实现
    • 从 XMLHttpRequest 到 Fetch API:前端网络请求演进与迁移指南
    • C++ 内存管理解析:现代视角下的核心机制与实践
    • 三款主流云电脑部署 DeepSeek 模型性能实测与对比
    • JavaScript 基础语法中篇:运算符、条件、循环与数组详解
    • Windows 下使用 VSCode 结合 WSL 实现远程开发及公网访问配置
    • DeepSeek R1 与 Janus-Pro 本地部署高级教程
    • ComfyUI 核心架构与 AI 绘画工作流实战
    • 使用 Playwright 封装 Web 爬虫并隐藏自动化特征

    相关免费在线工具

    • 加密/解密文本

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