双指针(Two Pointers)是一种常用的算法技巧,主要用于处理数组或链表等线性结构的问题。其核心思想是使用两个指针(或索引)来遍历数据结构,通过指针的移动来解决问题。
双指针的常见应用场景
- 有序数组的两数之和:在有序数组中查找两个数,使它们的和等于目标值。
- 移除元素:在数组中移除特定值的元素,同时保持原数组顺序。
- 反转数组或字符串:通过双指针从两端向中间遍历,实现反转。
- 链表中的环检测:使用快慢指针判断链表中是否存在环。
- 滑动窗口:通过双指针维护一个窗口,解决子数组或子字符串问题。
双指针的分类
- 同向双指针:两个指针从同一侧开始移动,通常用于滑动窗口或移除元素。
- 对向双指针:两个指针分别从两端向中间移动,适用于有序数组的两数之和或反转问题。
- 快慢指针:两个指针以不同速度移动,常用于链表中的环检测或找中点。
示例
1. 有序数组的两数之和
给定一个有序数组 nums
和目标值 target
,找到两个数使它们的和等于 target
。
1 2 3 4 5 6 7 8 9 10 11
| def two_sum(nums, target): left, right = 0, len(nums) - 1 while left < right: current_sum = nums[left] + nums[right] if current_sum == target: return [left, right] elif current_sum < target: left += 1 else: right -= 1 return []
|
2. 移除元素
给定一个数组 nums
和一个值 val
,移除所有等于 val
的元素,并返回新数组的长度。
1 2 3 4 5 6 7
| def remove_element(nums, val): slow = 0 for fast in range(len(nums)): if nums[fast] != val: nums[slow] = nums[fast] slow += 1 return slow
|
总结
双指针通过巧妙地移动两个指针来高效解决问题,通常能将时间复杂度从 (O(n^2)) 降低到 (O(n)),是一种非常实用的算法技巧。
好的!以下是使用 C++ 实现双指针的示例代码,涵盖两个经典问题:有序数组的两数之和 和 移除元素。
1. 有序数组的两数之和
给定一个有序数组 nums
和目标值 target
,找到两个数使它们的和等于 target
,并返回它们的下标。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include <iostream> #include <vector> using namespace std;
vector<int> 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 {left, right}; } else if (sum < target) { left++; } else { right--; } } return {}; }
int main() { vector<int> nums = {2, 7, 11, 15}; int target = 9; vector<int> result = twoSum(nums, target); if (!result.empty()) { cout << "Indices: " << result[0] << ", " << result[1] << endl; } else { cout << "No solution found!" << endl; } return 0; }
|
输出:
2. 移除元素
给定一个数组 nums
和一个值 val
,移除所有等于 val
的元素,并返回新数组的长度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include <iostream> #include <vector> using namespace std;
int removeElement(vector<int>& nums, int val) { int slow = 0; for (int fast = 0; fast < nums.size(); fast++) { if (nums[fast] != val) { nums[slow] = nums[fast]; slow++; } } return slow; }
int main() { vector<int> nums = {3, 2, 2, 3}; int val = 3; int length = removeElement(nums, val); cout << "New length: " << length << endl; cout << "Modified array: "; for (int i = 0; i < length; i++) { cout << nums[i] << " "; } cout << endl; return 0; }
|
输出:
1 2
| New length: 2 Modified array: 2 2
|
3. 快慢指针:链表的环检测
以下是一个使用快慢指针检测链表中是否存在环的示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| #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; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; if (slow == fast) { return true; } } return false; }
int main() { ListNode* head = new ListNode(3); head->next = new ListNode(2); head->next->next = new ListNode(0); head->next->next->next = new ListNode(-4); head->next->next->next->next = head->next;
if (hasCycle(head)) { cout << "Cycle detected!" << endl; } else { cout << "No cycle found." << endl; } return 0; }
|
输出:
总结
以上是 C++ 中双指针的三种经典应用:
- 对向双指针:用于有序数组的两数之和。
- 同向双指针:用于移除元素。
- 快慢指针:用于链表的环检测。
双指针技巧能够显著提高算法的效率,通常将时间复杂度从 (O(n^2)) 降低到 (O(n)),是解决线性结构问题的利器!