双指针
概念讲解
什么是双指针?
双指针是使用两个指针来解决问题的技巧,通常可以将 O(n²) 优化到 O(n)。
常见类型
| 类型 | 说明 | 应用 |
|---|---|---|
| 对撞指针 | 两端向中间移动 | 两数之和 |
| 快慢指针 | 速度不同 | 链表环检测 |
| 滑动窗口 | 维护窗口 | 子数组问题 |
对撞指针
123456789101112int left = 0, right = n - 1;
while (left < right) {
if (满足条件) {
// 处理
left++;
right--;
} else if (需要增大) {
left++;
} else {
right--;
}
}滑动窗口
123456789101112int left = 0;
for (int right = 0; right < n; right++) {
// 扩大窗口
window.add(nums[right]);
while (窗口需要收缩) {
window.remove(nums[left]);
left++;
}
// 更新答案
}考点分析
初赛考查方式
- 程序阅读: 双指针程序
- 编程题: 双指针应用
常见考点
- 两数之和
- 滑动窗口最大值
- 链表环检测
例题精讲
例题 1:两数之和
题目: 在有序数组中找两个数,使其和等于 target。
解答:
1234567int left = 0, right = n - 1;
while (left < right) {
int sum = a[left] + a[right];
if (sum == target) return {left, right};
else if (sum < target) left++;
else right--;
}例题 2:滑动窗口
题目: 求长度为 k 的子数组的最大和。
解答:
1234567int sum = 0, maxSum = 0;
for (int i = 0; i < k; i++) sum += a[i];
maxSum = sum;
for (int i = k; i < n; i++) {
sum += a[i] - a[i-k];
maxSum = max(maxSum, sum);
}练习题
- 双指针的时间复杂度是多少?
查看答案
O(n)
每个元素最多被访问一次,两个指针总共移动 n 次。
- 滑动窗口的适用场景是什么?
查看答案
滑动窗口适用于:
- 子数组/子串问题:求满足条件的最长/最短子数组
- 连续区间问题:求区间和、区间最值
- 字符串匹配:包含所有字符的最短子串
特点:窗口大小可变或固定,左右边界单调移动。
- 如何用快慢指针检测链表环?
查看答案
123456789101112131415bool hasCycle(ListNode* head) {
ListNode* slow = head;
ListNode* fast = head;
while (fast && fast->next) {
slow = slow->next; // 慢指针走一步
fast = fast->next->next; // 快指针走两步
if (slow == fast) { // 相遇说明有环
return true;
}
}
return false; // 快指针到末尾,无环
}易错点
⚠️ 注意:
- 对撞指针要求数组有序
- 滑动窗口要注意窗口大小
- 双指针通常将 O(n²) 优化到 O(n)
- 注意指针的移动条件