1 环形链表
141. 环形链表 - 力扣(LeetCode)
定义两个指针,一快一慢。慢指针每次只移动一步,而快指针每次移动两步。初始时,慢指针和快指针都在位置 head
,这样一来,如果在移动的过程中,快指针反过来追上慢指针,就说明该链表为环形链表。
使用 do-while
循环,可以把快慢指针的初始值都置为 head
。
class Solution {
public:bool hasCycle(ListNode *head) {ListNode* low = head, *fast = head;do {if(!fast || !fast->next)return false;low = low->next;fast = fast->next->next;}while(low != fast);return true;}
};
2 删除链表的倒数第 N 个结点
19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)
快指针先走n
步,慢指针后走(k-n
步)。
class Solution {
public:ListNode* removeNthFromEnd(ListNode* head, int n) {// 由于可能会删除链表头部,用哨兵节点简化代码ListNode* res = new ListNode(0, head);ListNode* low = res, *fast = res;while(n--) {fast = fast->next;}while(fast->next) {fast = fast->next;low = low->next;}// 左指针的下一个节点就是倒数第 n 个节点low->next = low->next->next;return res->next; }
};
3 环形链表II
142. 环形链表 II - 力扣(LeetCode)
参考题解:Krahets - 力扣(LeetCode)
使用快慢指针
-
fast
指针走过链表末端,说明链表无环,此时直接返回null
。 -
fast == slow
时,有环,且两指针在环中第一次相遇。将以上两式相减得到
s = nb
。而环的入口的表达式为:a + nb
,a
即从head
出发走到环入口的距离(步数),nb
即绕了几圈。又s = nb
,即慢指针再走a
步即可到达环入口。-
fast
走的步数是slow
步数的 2 倍,即f = 2s
;(解析:fast
每轮走 2 步) -
fast
比slow
多走了 n 个环的长度,即f = s + nb
;( 解析: 双指针在环内绕圈直到重合,重合时fast
比slow
多走环的长度整数倍 )。
-
-
令
fast
重新指向链表头部节点,此时f = 0
,s=nb
,令slow
和fast
同时每轮向前走 1 步。当两指针重合时,说明fast
和slow
都满足a + nb
。 即fast
指针走到f = a
,slow
指针走到s = a + nb
。 -
最后返回
slow
或fast
即可。
class Solution {
public:ListNode *detectCycle(ListNode *head) {ListNode* slow = head, *fast = head;do {if(!fast || !fast->next)return NULL;fast = fast->next->next;slow = slow->next;} while(fast != slow);// 此时 f = 2s, f = s + nb// 所以 s = nb// 而环入口节点表达式:a + nb// 所以让其在入口处汇合:fast = head;while(slow != fast) {fast = fast->next;slow = slow->next;}return slow;}
};