当前位置: 首页 > backend >正文

【C++ 双指针技巧】

文章目录

  • 一、什么是双指针?
  • 二、使用场景
    • 1. 删除数组中重复的元素(快慢指针)
      • ✅说明:
    • 2. 判断有序数组中是否存在两个数之和为 target(对撞指针)
      • ✅说明:
    • 3. 反转字符串(对撞指针)
      • ✅说明:
    • 4. 判断链表是否有环(快慢指针)
      • ✅说明:
    • 5. 盛最多水的容器(对撞指针)
      • ✅说明:
  • 三、双指针与暴力法的对比优势


一、什么是双指针?

双指针,顾名思义就是使用两个指针(或索引)来遍历数据结构,它可以分为两类:

  • 对撞指针(Two Pointers from Both Ends):两个指针从序列的两端向中间移动。
  • 快慢指针(Fast and Slow Pointers):两个指针从一端出发,以不同的速度移动。

这种技巧可以有效地降低时间复杂度,提升算法效率。


二、使用场景

1. 删除数组中重复的元素(快慢指针)

问题描述:给定一个有序数组 nums,原地删除重复出现的元素,使每个元素只出现一次,返回新数组的长度。

#include <iostream>
#include <vector>
using namespace std;int removeDuplicates(vector<int>& nums) {if (nums.empty()) return 0;int slow = 0;for (int fast = 1; fast < nums.size(); fast++) {if (nums[fast] != nums[slow]) {slow++;nums[slow] = nums[fast];}}return slow + 1;
}int main() {vector<int> nums = {1, 1, 2, 2, 3};int len = removeDuplicates(nums);cout << "去重后长度: " << len << endl;for (int i = 0; i < len; ++i)cout << nums[i] << " ";return 0;
}

✅说明:

  • fast 快指针向前扫描;
  • slow 慢指针维护已去重序列的尾部。

2. 判断有序数组中是否存在两个数之和为 target(对撞指针)

问题描述:给定一个升序数组 nums 和一个整数 target,判断数组中是否存在两个数的和等于 target

#include <iostream>
#include <vector>
using namespace std;bool twoSum(vector<int>& nums, int target) {int left = 0, right = nums.size() - 1;while (left < right) {int sum = nums[left] + nums[right];if (sum == target) return true;else if (sum < target) left++;else right--;}return false;
}int main() {vector<int> nums = {1, 2, 4, 7, 11, 15};int target = 15;cout << (twoSum(nums, target) ? "存在" : "不存在") << endl;return 0;
}

✅说明:

  • leftright 从两端出发,寻找匹配组合;
  • 特别适用于有序数组

3. 反转字符串(对撞指针)

问题描述:将字符串原地反转。

#include <iostream>
#include <vector>
using namespace std;void reverseString(vector<char>& s) {int left = 0, right = s.size() - 1;while (left < right) {swap(s[left++], s[right--]);}
}int main() {vector<char> s = {'h', 'e', 'l', 'l', 'o'};reverseString(s);for (char c : s) cout << c;return 0;
}

✅说明:

  • swap 的使用要特别注意 ++-- 的顺序;
  • 通常在需要原地修改结构时非常实用。

4. 判断链表是否有环(快慢指针)

问题描述:给定一个链表,判断链表中是否有环。

#include <iostream>
using namespace std;struct ListNode {int val;ListNode* next;ListNode(int x): val(x), next(nullptr) {}
};bool hasCycle(ListNode* head) {if (!head || !head->next) return false;ListNode* slow = head;ListNode* fast = head->next;while (fast && fast->next) {if (slow == fast) return true;slow = slow->next;fast = fast->next->next;}return false;
}

✅说明:

  • fast 一次走两步,slow 一次走一步;
  • 若存在环,快慢指针终将相遇。

5. 盛最多水的容器(对撞指针)

问题描述:给定一个数组 height[] 表示每个柱子的高度,找到两个柱子之间能容纳的最大水量。

#include <iostream>
#include <vector>
using namespace std;int maxArea(vector<int>& height) {int left = 0, right = height.size() - 1;int maxWater = 0;while (left < right) {int h = min(height[left], height[right]);maxWater = max(maxWater, h * (right - left));if (height[left] < height[right]) left++;else right--;}return maxWater;
}int main() {vector<int> height = {1,8,6,2,5,4,8,3,7};cout << "最大容量: " << maxArea(height) << endl;return 0;
}

✅说明:

  • 双指针在左右两端向中间靠拢;
  • 每次根据高度判断该移动哪一侧。

三、双指针与暴力法的对比优势

方法时间复杂度适用情况
暴力法O(n²)无序数组,无法优化
双指针法O(n) 或 O(nlogn)有序结构、可跳跃遍历

在查找两个数之和的情况下,暴力法需要两层循环,而双指针只需一次遍历。

http://www.xdnf.cn/news/20368.html

相关文章:

  • 嵌入式学习笔记--Linux系统编程阶段--DAY06进程间通信-消息队列
  • Linux知识回顾总结----文件系统
  • 南科大适应、协同与规划的完美融合!P³:迈向多功能的具身智能体
  • 【基础-单选】下面哪一个事件方法可以获取到List滑动的偏移量
  • Flicking单图轮播无法拖动的问题
  • c++primer 个人学习总结-模板和泛型编程
  • 《QDebug 2025年8月》
  • 前端开发学习路径
  • LeetCode 468. 验证IP地址 - 详细解析
  • 嵌入式学习笔记--Linux系统编程阶段--DAY07进程间通信--存储映射和共享内存
  • 区块链技术
  • 如何减少微型导轨表面破损情况?
  • JWT概念及使用详解
  • Dart语言基础 关键字 var与dynamic
  • 整车无线布置的综述
  • 【完整源码+数据集+部署教程】室内场景分割系统源码和数据集:改进yolo11-DWR
  • 算法题(200):最大子段和(动态规划)
  • 责任链框架 03:处理器实现
  • 《Science》神经炎症综述思路套用:从机制到跨领域研究范式
  • Python实现生成矩形框、三角形框、六边形框和圆环点云
  • 自动拆箱和装箱的原理与作用
  • HMI(人机界面)
  • 【基础-单选】UIAbility实例创建完成时触发的回调
  • HTML 列表类型
  • 5-8单元格区域与VS数组应用(实例:提取满足条件的数据)
  • Qt多线程编程学习
  • EG2103 SOP-8 内置600V功率MOS管 栅极驱动芯片
  • I/O 多路复用 (I/O Multiplexing)
  • 四个关于云属性的四个卫星数据集的介绍
  • 基于Spring Boot + Vue3的办公用品申领管理系统