前言
转载自kirsche在 leetcode-cn 142.的题解
经典题目,142.环形链表Ⅱ
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
。
一般用快慢指针来解决此类问题,例如寻找距离尾部第K个节点、寻找环入口、寻找公共尾部入口等。
算法思路
假设链表有环,fast和slow从head出发,fast指针一次前进两步,slow指针一次前进一步,因为有速度差,最终两指针一定会在环中相遇。
1、两个指针第一次相遇
设链表共有a+b个节点(环上b个),假设两指针相遇时,fast走了f步,slow走了s步,则有如下关系:
- f=2s
- f-s=nb ,即fast比slow多走了n倍的环的长度
化简以上两式,s=nb,即slow走了n倍的环周长
2、如何得出环的入口节点?
每一次走道环的入口节点,走过的步数都满足k=a+nb,而此时slow指针已经走了nb,也就是说slow指针再走a步,则一定位于环的入口节点。
3、让fast和slow第二次相遇
如何能让slow指针精准走a步呢?
答:令fast从head重新出发,slow从之前相遇点出发。此时f=0,s=nb。当f=a, s=a+nb时,此时两指针再次相遇,并且都指向环的入口节点;
代码
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
|
class Solution { public: ListNode *detectCycle(ListNode *head) { ListNode *fast = head, *slow = head; while (1){ if (fast == NULL || fast->next == NULL) return NULL; fast = fast->next->next; slow = slow->next; if (fast == slow) break; } fast = head; while (fast != slow){ fast = fast->next; slow = slow->next; } return fast; } };
|
其它例题
问题描述:
给定一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
示例:
1 2
| 输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5]
|
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Solution { public: ListNode* removeNthFromEnd(ListNode* head, int n) { ListNode *p = new ListNode(); p->next = head; ListNode *fast = p, *slow = p; while (n --) { fast = fast->next; } while (fast != nullptr && fast->next != nullptr) { slow = slow->next; fast = fast->next; } slow->next = slow->next->next; return p->next; } };
|
以上代码中,利用了前置哨兵节点p
,是针对“删除首节点的情况”。
📔博文图谱
提及本博文的链接