双指针算法是一种高效的编程技巧,通常用于解决线性数据结构(如数组、链表)中的特定问题。这种算法的核心思想是利用两个或多个指针在数据结构中按不同策略移动,并通过它们的相对位置和指向的数据关系来解决问题。
基本类型:
-
快慢指针 (Fast-Slow Pointers):
- 用于检测循环链表:设置两个指针,一个每次前进一格,另一个每次前进两格。如果存在环,则快指针最终会追上慢指针。
- 计算链表的中点:同样基于快慢指针速度差原理,当快指针到达尾部时,慢指针所在位置即为中点。
- 求解链表环的起点和长度:结合上述方法,在快慢指针相遇后,将慢指针重置到头结点,快慢指针以相同速度再次前进,相遇点即为环入口。
-
左右指针/对撞指针 (Two-Pointer):
- 在有序数组中查找目标值对:例如,LeetCode上的题目“两数之和”系列,其中一个指针从左向右扫描,另一个从右向左扫描,寻找满足条件的元素对。
- 删除排序数组中的重复项:一个指针作为读取器,另一个作为写入器,只将不重复的元素复制到新位置。
- 检查回文字符串:使用两个指针分别从首尾开始遍历字符串,若所有对应位置字符相等,则字符串为回文。
应用场景举例:
1. 两数之和 (LeetCode #1)
#include <vector>
using namespace std;
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> hash_map;
for (int i = 0; i < nums.size(); ++i) {
int complement = target - nums[i];
if (hash_map.find(complement) != hash_map.end()) {
return {hash_map[complement], i};
}
}
// 如果没有找到符合条件的解,则返回空向量(在LeetCode中不需要)
return {};
}
// 示例使用:
int main() {
vector<int> nums = {2, 7, 11, 15};
int target = 9;
vector<int> indices = twoSum(nums, target);
if (!indices.empty()) {
cout << "Indices: " << indices[0] << ", " << indices[1] << endl;
} else {
cout << "No solution found." << endl;
}
return 0;
}
2. 有序数组中的第一个大于等于给定值的元素索引
#include <vector>
using namespace std;
int search_first_ge(const vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] >= target) {
if (mid == 0 || nums[mid - 1] < target) {
return mid;
}
right = mid - 1;
} else {
left = mid + 1;
}
}
// 如果没有找到符合条件的元素,则返回-1
return -1;
}
// 示例调用
int main() {
vector<int> nums = {1, 3, 4, 6, 8, 9};
int target = 6;
int index = search_first_ge(nums, target);
cout << "First index greater or equal to " << target << ": " << index << endl;
return 0;
}
3. 检查回文字符串
#include <iostream>
#include <string>
using namespace std;
bool is_palindrome(string s) {
int left = 0, right = s.length() - 1;
while (left < right) {
if (s[left] != s[right]) {
return false;
}
++left;
--right;
}
return true;
}
// 示例调用
int main() {
string s = "racecar";
if (is_palindrome(s)) {
cout << s << " is a palindrome." << endl;
} else {
cout << s << " is not a palindrome." << endl;
}
return 0;
}