今天要分享的关于链表的题目是环形链表
目录
题目141. 环形链表 - 力扣(LeetCode)
题解
关于快慢指针的深入研究
题目2:142. 环形链表 II - 力扣(LeetCode)
题解
以下是题目链接
141. 环形链表 - 力扣(LeetCode)
题目141. 环形链表 - 力扣(LeetCode)
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
题目给出了三种示例
给出了这么多示例无非就是想告诉我们结点在环中是无法确定的。
首先我们可以确定正常的链表可以遍历结束,但是带环链表不能用循环来解决问题,因为链表是环形的,闭环会形成死循环;
题解
我们不妨定义一个快指针和慢指针来解决问题,顾名思义,快指针就是向后迭代比较快的指针,而慢指针就是迭代较慢的指针,我们也可以理解为追及问题;
所以让slow(慢指针)一次走一步,fast(快指针)一次走两步
我们可以看到当两个指针进入到环中时就一直会在循环当中直到相遇,就像追及问题一样很好理解;
同样的反过来看如果快慢指针相遇了,那就说明这个链表带环;
以下是本题代码
bool hasCycle(struct ListNode *head) {
struct ListNode *slow=head;
struct ListNode *fast=head;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
if(slow==fast)
{
return true;
}
}
return false;
}
要理解起来也不算困难
1.首先定义两个结构体类型的快慢指针;
2.因为快指针走的比较快,他也起着“探路”的作用,所以可以利用快指针和快指针指向的下一个结点是否为空作为判断条件,不为空就让slow走一步,fast走两步;
3.最后再加以判断,如果快慢指针指向的位置相同,就说明有环,返回ture,否则则无环,返回false;
以上就是题目的题。
接下来我们要讨论关于这道题的逻辑问题
关于快慢指针的深入研究
我们在理解题目的时候一定会出现这样的问题
1.在带环链表中slow和fast指针一定会相遇吗?
2.一定slow走一步和fast走两步吗?其他步数(2以上的)是否也会相遇?
先说结论,上面我们就证明过了,当slow走一步fast走两步时,是一定会相遇的。
我们继续画图说明
因为fast会先进环,且fast追slow,所以假设slow进环时slow和fast之间的距离是N;
当slow向前走一步时,fast向前走两步,这时再次计算两个指针之间的距离就变成了N-1,这里应该不难理解;
也就是说当两个指针进环之后,fast开始追及slow,slow每走一步fast就走两步,两者之间距离就缩小1,就这样以此类推N,N-1,N-2,......3,2,1,0。当距离为0的时候就说明fast已经追上了slow
接下来当我们将fast快指针的步数固定为三步的时候快慢指针是否还会相遇呢?
先说结论,不一定相遇。
和上面一样两个指针进环时开始追及;
和上面不同的是fast走三步的时候,两个指针之间的距离就减少2,所以两者之间的距离为N,N-2,N-4,.....以此类推。当两者之间开始的距离是偶数的时候会相遇,但是当两者的距离是奇数的时候会出现负数,出现负数就意味着错过,再新一轮追及时就会越来越远;
接下来继续深入研究环形链表的题目
题目2:142. 环形链表 II - 力扣(LeetCode)
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
题解
既然都是环形链表的问题,我们不妨继续使用双指针来解决问题。以下为本题代码
我们可以让一个指针从相遇点开始走,另一个指针从链表头开始走,那么他们就会在入口点相遇;那么以下就是对这个结论的推理
这道题的意思就是求环的入口点,我们继续画图理解
我们上面规定fast的速度是slow的两倍,如图:
我们可以再新定义一个结点meet,用来表示两个两个指针相遇的地方
x用来表示环的入口点和相遇点的距离;
L表示链表头到环入口的距离;
C来表示环的周长;
所以我们可以得出slow走的路程是L+x;
因为fast和slow之间的距离每走一步就缩小1,所以可以知道fast在一圈之内一定可以和slow相遇;
fast所走的路程是:L+C+x;
又因为fast的速度是slow的两倍,所以fast所走的路程也可以是2(L+x);
这样就有如下关系
2(L+x)=L+C+x
也可以是L+x=n*x,这里n就是圈数,
所以L=n*C-x=(n-1)*C+C-x;
以上就是对推论的原理
以上就是两道关于链表的题目,希望在链表的学习中对你有所帮助