Leecode141. 环形链表
题目介绍
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
题目分析
这就是典型的快慢指针追击问题,就定义两个快慢指针,在有环的情况下,快指针走两步,慢指针走一步,结果快指针一定会追上慢指针。
那么为什么慢指针要走一步,快指针要走两步才能追上慢指针呢?为什么三步,走四步,甚至N步就不行呢?
假设是一个有环的链表,fast一定会先进环,slow就后进环,等slow进环的时候,可能fast就已经要追上slow了。
就算是最坏的情况,slow刚好进环的时候,fast就在slow的前面,之间的距离差了将近一个环
就像这样
就算这样,两个指针每移动一次的话,它们之间的距离拉近一步,最后slow走了R - 1 步(假设环长R),fast也追上了slow。
但是fast一次走三步,slow一次走一步的话
如果环是这样,那么阁下如何应对?
这样就永远不会相遇,因为fast把slow套圈了。
所以说,fast走两步,slow走一步就一定可以相遇滴
代码实现
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool hasCycle(struct ListNode *head) {
struct ListNode *fast = head;
struct ListNode *slow = head;
while(fast != NULL && fast -> next != NULL)
{
fast = fast -> next ->next;
slow = slow -> next;
if(fast == slow)
{
return true;
}
}
return false;
}
Leecode142. 环形链表II
题目介绍
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改链表。
题目分析
先根据题目,得到能够计算出来的点
解释点:
H = 链表头
pos = 进环的点(也就是题目要求的点)
M = fast 和 slow相遇的点
设:H ~ pos : 距离为L
pos ~ M : 距离为X
环长:R
由上面就能得到:
M ~ pos:距离为R - X
fast走的路程:L + X + nR(n为圈数)
slow走的路程:L + X
根据fast一次走两步,slow一次走一步则有能得到的表达式:
2 fast= slow
2(L + X + nR)= L + X
—>L = nR - X
在极端条件下,假设n为1(无论如何,n最小为1,因为等slow进环后,fast一定在slow的前面,就要跑了一圈才能追上)
故:L = R - X
**L = R - X的含义就是:**两个指针分别从H点和M点同时出发,每次移动一步的话,那么就会在进环点相遇
代码实现
- 找到M点(fast 和 slow相遇的点)
- 让两个指针分别从H点和M点同时出发,每次移动一步
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode *fast = head;
struct ListNode *slow = head;
// 找到相遇点M
while(fast != NULL)
{
if(fast -> next == NULL)
{
return NULL;
}
fast = fast -> next -> next;
slow = slow -> next;
// 让让两个指针分别从H点和M点同时出发,每次移动一步
if(fast == slow)
{
struct ListNode *q = slow;
struct ListNode *p = head;
while(p != q)
{
p = p -> next;
q = q -> next;
}
return p;
}
}
return NULL;
}
小结
总之环形链表入门还是很简单的,就是用双指针来解决就好了,难一点就寻找变量关系来得到表达式,最后得出题目的数学关系