双指针算法精解:对撞指针与快慢指针的妙用与实践
“ 在算法学习中,双指针技巧是一种高效且实用的方法,能够显著降低时间复杂度,优化代码性能。”
本文将深入探讨两种经典的双指针技术:对撞指针与快慢指针,帮助你掌握其核心思想与应用场景。
01
—
对撞指针(Colliding Pointers)
1.细节
- 定义:对撞指针使用两个指针,一个从数组的起始位置(左指针)开始,另一个从数组的末尾(右指针)开始,两个指针向中间移动,直到相遇或交叉。
- 适用场景:通常用于有序数组或可以通过排序转化为有序数组的问题。
- 时间复杂度:O(n),因为每个指针最多遍历数组一次。
2.思想
- 核心思想:通过左右指针的协同移动,缩小问题的搜索范围。利用数组的有序性,通过比较指针指向的值与目标值的关系,决定移动哪个指针。
- 优势:避免了暴力搜索的高时间复杂度(O(n^2)),将问题优化为线性时间复杂度。
3.功能
- 典型应用:
- 两数之和:在有序数组中找到两个数,使它们的和等于目标值。
- 三数之和:找到数组中三个数,使它们的和等于目标值。
- 回文串判断:判断一个字符串是否为回文串。
4.代码示例
#include <vector> #include <algorithm> // 两数之和问题 std::vector<int> twoSum(std::vector<int>& nums, int target) { std::sort(nums.begin(), nums.end()); // 首先对数组排序 int left = 0; int right = nums.size() - 1; while (left < right) { int sum = nums[left] + nums[right]; if (sum == target) { return {nums[left], nums[right]}; // 返回找到的两个数 } else if (sum < target) { left++; // 和小于目标值,左指针右移 } else { right--; // 和大于目标值,右指针左移 } } return {}; // 如果没有找到,返回空数组 }
02
—
左右指针(快慢指针,Slow-Fast Pointers)
1.细节
- 定义:快慢指针使用两个指针,一个移动速度快(快指针),另一个移动速度慢(慢指针)。通常快指针每次移动两步,慢指针每次移动一步。
- 适用场景:常用于链表或数组中的循环检测、中点查找、滑动窗口等问题。
- 时间复杂度:O(n),因为每个指针最多遍历链表或数组一次。
2.思想
- 核心思想:通过快慢指针的速度差,解决一些需要定位特定位置或检测特定模式的问题。例如,快指针的速度是慢指针的两倍,可以用来找到链表的中点或检测环。
- 优势:避免了额外的空间开销(如使用哈希表),同时保持线性时间复杂度。
3.功能
- 典型应用:
- 链表环检测:判断链表中是否存在环。
- 链表中点查找:找到链表的中点。
- 滑动窗口:解决子数组或子字符串的相关问题。
4.代码示例
#include <iostream> struct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(nullptr) {} }; // 链表环检测 bool hasCycle(ListNode* head) { if (head == nullptr || head->next == nullptr) { return false; } ListNode* slow = head; // 慢指针 ListNode* fast = head; // 快指针 while (fast != nullptr && fast->next != nullptr) { slow = slow->next; // 慢指针每次移动一步 fast = fast->next->next; // 快指针每次移动两步 if (slow == fast) { return true; // 快慢指针相遇,说明有环 } } return false; // 无环 } // 链表中点查找 ListNode* findMiddle(ListNode* head) { ListNode* slow = head; ListNode* fast = head; while (fast != nullptr && fast->next != nullptr) { slow = slow->next; // 慢指针每次移动一步 fast = fast->next->next; // 快指针每次移动两步 } return slow; // 慢指针指向中点 }
03
—
总结
类型 | 细节 | 思想 | 功能 |
对撞指针 | 两个指针从两端向中间移动,适用于有序数组。 | 利用有序性缩小搜索范围,优化时间复杂度。 | 两数之和、三数之和、回文串判断等。 |
左右指针 | 快慢指针以不同速度移动,适用于链表或数组。 | 通过速度差定位特定位置或检测特定模式。 | 链表环检测、链表中点查找、滑动窗口等。 |
双指针技术是一种非常实用的算法设计思想,能够有效解决许多经典问题。掌握对撞指针和左右指针的使用场景和实现细节,可以显著提升算法能力。
C/C++ 文章被收录于专栏
记录我的C++学习路程