昨天不是写了一篇有关链表的数据结构练习题嘛,其实那篇文章的第二道题还有许多值得我们思考的东西,今天就在这做一个简短的补充。补充一下运用那道题解决另一道题。
给大家看一下绿色让眼睛放松一下。
给定一个链表的头节点 head
,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
这道题跟我说的昨天第二道题十分相似,但确实它的进阶版,这里我们要解决的是,除了判断它是否有环,还需找出它的环是哪个节点,这样一看,这题目好像确实是难上加难了,但是问题总是有对应的方法去解决的,这里我们不得不先丢出一个结论,大家先看等下我再解释。
结论: 一个指针从相遇的点走,另一个从链表的开头走,那么这两个指针一定会在入环的节点相遇。
那么现在我们给大家证明一下这个结论:
我们设不为环的地方为L,环的周长为C,N为正整数变量, 那么我们知道L的距离要么使C-X,异或N*C-X,那么只要相遇那么只要两指针往后走,那就一定可以在入环的位置相遇。
那么这时我们就可以根据这个结论解决这道题目了。
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode *detectCycle(struct ListNode *head) { if(head==NULL) { return NULL; } struct ListNode * fast=head; struct ListNode * slow=head; while(fast && fast->next) { fast=fast->next->next; slow=slow->next; if(slow==fast) { struct ListNode *meet=fast; while(head!=meet) { head=head->next; meet=meet->next; } return meet; } } return NULL; }
代码解析:我们通过第一个while循环找到有环链表的相遇位置meet,然后我们就可以让head和meet开始走,直到相遇,那么这个相遇的位置就是环的入口位置了。
那么这篇文章就结束了。