目录
双指针法常用与题型:数组、字符串、链表、N数之和
一、left right在一个循环里
left right在一个循环里。
left和right移动需要条件,一般是向中间移动left++,right--。对于二分法向middle位置移动。
34. 在排序数组中查找元素的第一个和最后一个位置:不用二分法会简单一点,单步移动的,而且注意for中return行的位置
344. 反转字符串:注意使用swap(char,char)函数
54. 替换数字(第八期模拟笔试):如果为了不用额外的辅助空间,可以先计算总长度,left指针倒序遍历旧数组,right指针倒序填写新数组。
15. 三数之和:值得回顾
18. 四数之和:值得回顾11. 盛最多水的容器:left和right谁小就移动谁
167. 两数之和 II - 输入有序数组有序数字,找两数之和,和小left++,和大right--
二、两个指针在各自的循环里
两个指针分别在各自的循环里,为了记录特征索引
941. 有效的山脉数组:left right两个指针各相对而行跑一遍,找出山峰位置,最后判断left和right能不能相遇
面试题 02.07. 链表相交:两个指针各跑一遍,为了找出两个链表的长度差
三、slow fast追逐型
slow和fast的速度不同(一般slow速度1,fast速度2),或者初始位置不同
链表:
143. 重排链表:slow速度1,fast速度2,可以方便的找到中心链表
面试题 02.07. 链表相交142. 环形链表 II:slow速度1,fast速度2,可以解决环形链表找入环位置
19. 删除链表的倒数第 N 个结点:fast先走n,slow再走n,可以找到倒数第n个节点
四、slow fast条件型
fast无脑++,而slow需要满足一定条件才能保存元素后++
数组
283. 移动零:向这种要原地修改的一看就像是要用双指针
这里有一个需要反方向遍历的:88. 合并两个有序数组
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
sort(nums.begin(), nums.end());
// 找出a + b + c = 0
// a = nums[i], b = nums[left], c = nums[right]
for (int i = 0; i < nums.size(); i++) {
// 排序之后如果第一个元素已经大于零,那么无论如何组合都不可能凑成三元组,直接返回结果就可以了
if (nums[i] > 0) {
return result;
}
// 错误去重a方法,将会漏掉-1,-1,2 这种情况
/*
if (nums[i] == nums[i + 1]) {
continue;
}
*/
// 正确去重a方法
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int left = i + 1;
int right = nums.size() - 1;
while (right > left) {
// 去重复逻辑如果放在这里,0,0,0 的情况,可能直接导致 right<=left 了,从而漏掉了 0,0,0 这种三元组
/*
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
*/
if (nums[i] + nums[left] + nums[right] > 0) right--;
else if (nums[i] + nums[left] + nums[right] < 0) left++;
else {
result.push_back(vector<int>{nums[i], nums[left], nums[right]});
// 去重逻辑应该放在找到一个三元组之后,对b 和 c去重
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
// 找到答案时,双指针同时收缩
right--;
left++;
}
}
}
return result;
}
};