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

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

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

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

引言

在算法题中,双指针技巧是一类高频且实用的解题方法。它并非真正的'指针',而是通过两个数组下标(或迭代器)的协同移动,在数组划分、区间求解、环检测等场景中实现高效遍历与逻辑处理,往往能将时间复杂度从暴力法的 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. 三数之和
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

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

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

更多推荐文章

查看全部
  • SpringAI 与 Deepseek 大模型应用开发实战笔记(上)
  • 基于 Leaflet Trackplayer 的高速公路轨迹 WebGIS 可视化
  • 深入理解前端防抖与节流:原理、区别与实战示例
  • 2025 年 AIGC 六大核心趋势与应用场景
  • LLaMA3 微调教程:LLaMA Factory 安装部署、模型微调与 GGUF 转换
  • Flutter 与 Web 混合开发方案与实践
  • HarmonyOS 网络请求实战:Axios 集成与用户列表交互
  • 2026 春晚透视 AI 趋势:智能体元年与普通人应对策略
  • QUEST 一体机 SideQuest 安装 APK 与 OBB 数据包教程
  • Xilinx FPGA 驱动 USB3.0 外设实战指南
  • 2025 AI 产业全景深度解析与未来趋势洞察
  • Vue 前端综合面试题整理
  • Android 开发实战:如何在 TextView 中应用 TTF 自定义字体
  • OpenClaw 配置本地 Ollama 模型实现离线 AI 助理
  • AI 辅助 9·1 软件安装:环境检测与问题修复方案
  • Z-Image-Turbo 镜像快速搭建与 AI 绘画教学指南
  • Python 基础命令与语法详解
  • Microsoft Edge WebView2 运行库下载与安装指南
  • llama.cpp 性能调优指南:提升本地部署效率
  • AgentScope Java 与 Spring AI Alibaba Workflow 集成指南

相关免费在线工具

  • 加密/解密文本

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