快慢指针主要用于链表相关的问题
1.寻找链表中部
思路:设置慢指针步长为1,快指针步长为2,同时出发,当快指针到尾部时,慢指针到了中部;需要注意链表个数是奇数还是偶数
ListNode * searchMid(ListNode * L1)
{//寻找链表的中间节点
//使用快慢指针
if (L1 == nullptr || L1->next == nullptr) return L1; //无节点或只有单个节点时
ListNode * slow = L1;
ListNode * fast = L1;
while (slow->next != nullptr&&fast->next!= nullptr&&fast->next->next != nullptr)
{
slow = slow->next;
fast = fast->next->next;
}
if (fast->next == nullptr) return slow;//节点总数为奇数
else return slow->next;//节点总数为偶数
}
2.判断是否是回文链表
思路:设置慢指针步长为1,快指针步长为2,同时出发,将慢指针遍历的节点入栈,当快指针到尾部时,慢指针到了中部;需要注意链表个数是奇数还是偶数;
之后再将栈中数据与慢指针比较,相同则为回文
bool palindromic(ListNode * L1)
{//判断链表是否是回文
//使用快慢指针
if (L1 == nullptr || L1->next == nullptr) return true; //无节点或只有单个节点时
ListNode * slow = L1;
ListNode * fast = L1;
stack<ListNode *> forward;
while (slow->next != nullptr&&fast->next != nullptr&&fast->next->next != nullptr)
{
forward.push(slow);//将前半个链表的指针入栈
slow = slow->next;
fast = fast->next->next;
}
//后半个链表与栈中前半个链表比较
if (fast->next == nullptr)//节点总数为奇数,
{
slow = slow->next;//中间节点无须比较,例如(1,2,1)中的2
}
//否则节点总数为偶数
while (slow->next != nullptr)
{
if (slow->next != forward.top()) return false;//一旦出现不符合的情况就不是回文
forward.pop();
slow = slow->next;
}
return true;
}
3.判断链表是否有环、以及环的入口
思路:设置慢指针步长为1,快指针步长为2,(这里快指针步长设置长一点也可以,但是可能会导致更慢地遇到慢指针,所以步长2比较科学)同时出发,当快慢指针相遇,说明有环。第一次相遇后将步长设置为1,一个从开始节点出发,一个从相遇节点出发,再次相遇的节点则是环的入口
ListNode * searchRound(ListNode * L1)
{//寻找链表的回环,如果存在的话返回环的入口否则返回空
//使用快慢指针
if (L1 == nullptr ) return nullptr; //无节点时
//if (L1->next == L1) return L1;//单个节点指向自己时
ListNode * slow = L1;
ListNode * fast = L1;
while (slow->next != nullptr&&fast->next != nullptr&&fast->next->next != nullptr)
{
slow = slow->next;
fast = fast->next->next;
if (slow == fast)//第一次相遇,说明有环
{
slow = L1;//从头开始重新遍历
break;
}
}
while (slow->next != nullptr&&fast->next != nullptr)
{
slow = slow->next;
fast = fast->next;
if (slow == fast)//第二次相遇,是环的入口
{
return slow;
}
}
return nullptr; //无环
}
小知识点:&&从左到右有熔断机制(短路机制),当左边一旦有一个是false,右边会直接跳过不去运行。
4.删除倒数第n个节点
思路:让快指针先跑n步,然后再一起跑