一,快慢指针
快慢指针也被称为Hare&Tortoise算法,两个在数组(链表)中以不同速度移动的指针。
- 应用场景:
- 处理链表或数组中的循环的问题,例如判断链表是否为环状
- 找链表中点或需要知道特定元素的位置
- leetcode141环形链表
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode* fast=head;
ListNode* slow=head;
while(fast&&fast->next){
fast=fast->next->next;
slow=slow->next;
if(fast==slow)
return true;
}
return false;
}
};
- leetcode142,返回入环的第一个节点
用快慢指针可以判断出链表是否有环,
假设在z 点 fast指针和slow 指针相遇。x-y 长度为a, y-z 长度为 b , z-y 长度为c。
则:slow 指针走了 a+b 的距离。 fast 指针走了 a + n(b + c)+ b 的距离。(可能不仅绕了一圈而是绕环走了n圈)
fast指针的速度是slow 指针速度的2倍。 所以a + b + n(b + c) = 2 (a + b), 简化得 a+b = n(b + c)。 因为我们想要求 a 的距离, 所以我们移动方程 得到 a = (n-1)b + n c 。
仔细观察上面的等式。 考虑它的含义, 即c 总比b 多一次, 这就意味着, 我们再放两个指针, first放在x ,second放在z ,这次保持速度一致, first 跑到y , second 也会跑到y。所以,当它们相遇,就是cycle的起点。
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* slow=head;
ListNode* fast=head;
while(fast&&fast->next){
slow=slow->next;
fast=fast->next->next;
if(fast==slow){
ListNode *l1=head;
ListNode *l2=fast;
while(l1!=l2)
{
l1=l1->next;
l2=l2->next;
}
return l1;
}
}
return 0;
}
};
- leetcode 234判断是否为回文链表
思路:先使用快慢指针找到中点,把前半部分逆转,再和后半部分链表逐个比较
class Solution {
public:
bool isPalindrome(ListNode* head) {
if(!head || !head->next)
return 1;
ListNode *fast = head, *slow = head;
ListNode *p, *pre = NULL;
while(fast && fast->next){
p = slow;
slow = slow->next; //快慢指针,寻找链表的中点
fast = fast->next->next;
p->next = pre; //遍历慢指针,且翻转
pre = p;
}
if(fast) //奇数个节点时,fast为最后一个节点,需跳过中间节点;偶数个节点,fast为NULL
slow = slow->next;
while(p){ //前半部分和后半部分比较
if(p->val != slow->val)
return 0;
p = p->next;
slow = slow->next;
}
return 1;
}
};
二,双指针
指的是在遍历对象的过程中,不是普通的使用单个指针进行访问,而是使用两个相同方向(快慢指针)或者相反方向(对撞指针)的指针进行扫描,从而达到相应的目的。这里指左右指针。
二分查找,两数之和,反转数组,滑动窗口