今天我们来看一下链表的经典问题,带环问题
这个问题可以算是比较经典的面试题了,接下来咱们看看题目内容
看到这个题目,首先我们应该想到的思路,就是“快慢指针”;
-
让快慢指针slow 和 fast 都为head,随后将让fast以slow的两倍速度进行移动,具体如下图
-
然后注意判断,如果是不带环的链表,那么fast或者fast->next中肯定会有一个为空指针,如下图所示
此时代码可以写为:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool hasCycle(struct ListNode *head) {
struct ListNode* slow=head,*fast = head;
while(fast&&fast->next)//判断是否带环,以fast为判断条件
{
slow = slow->next;
fast = fast->next->next;
}
return false;
}
之后我们需要解决while循环中的代码,此时我们需要找到规律
-
当fast和slow走到环内,一共有两种情况,一种是走着相交,一种是永不相交,此时我们需要判断是哪种情况
1.当fast指针的速度是slow的两倍,那么fast追赶slow,(设fast和slow之间的距离为N),N(偶数)的距离就是N -> N-1 -> N-2 ..... N-(N-1) -> 0,所以在这种情况下,N的值肯定为0。所以肯定相交。
2.当fast的指针速度是slow的三倍,那么fast追赶slow,N的距离N-2 -> N-4 ->N-6 ..... N-(N-1) -> -1
在这种情况下,就要进入第二次追赶(设环的长度为C)如果C为奇数,那么就需要走N+1的距离
又因为N+1是偶数,所以在C为奇数时,fast和slow会相交。
如果C为偶数,那么fast和slow就不可能相交。
- 其实我们需要一个公式就可以知道,C不可能在是N为偶数的情况下为奇数
设head到环入口节点位置的距离为L,fast到slow的距离为N,环的长度为C
3*L = L+x*C+C-N
2*L = (x+1)C-N
从此得出,在两边都为偶数的情况下,C不可能为奇数
即永远相交
那么我们补完代码即可解答这个问题。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool hasCycle(struct ListNode *head) {
struct ListNode* slow=head,*fast = head;
while(fast&&fast->next)//判断是否带环,以fast为判断条件
{
slow = slow->next;
fast = fast->next->next;
if(fast == slow)
return true;
}
return false;
}
附加问题(变题)
这次我们重新设,并且用表达式解决
假设fast和slow已经相遇,N,L和C不变(fast为slow速度的两倍)。得出:
2*L=L+x*C+N
L=x*C+N
不管x为何数,以head和slow或fast节点为头开始走都会同时走到环头节点,此时可以写出代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool hasCycle(struct ListNode *head) {
struct ListNode* slow=head,*fast = head;
while(fast&&fast->next)//判断是否带环,以fast为判断条件
{
slow = slow->next;
fast = fast->next->next;
if(slow == fast){
struct ListNode* meet = slow
while(meet!=head)
{
head = head->next;
meet = meet->next;
}
}return head;
return NULL;
}
那么这题就全部解答完成啦。
咱们下次再见哦