141.环形链表
题目描述:
分析:
可以定义两个指针:快指针,慢指针。若有环,则当慢指针进入环后,快指针总会追上慢指针与之相遇。
代码如下:
bool hasCycle(struct ListNode *head) {
struct ListNode*fast, *slow;//定义快慢指针
fast = slow = head;//都从头开始走
//若不成环则fast指针会先走到尾,指向空,则停止。
//fast && fast->next 为链表元素为奇和偶的情况
while(fast && fast->next){
slow = slow->next;
fast = fast->next->next;
if(fast == slow){
return true;
}
}
return false;
}
142.环形链表II
题目描述:
这题的正常思路是记录每个节点位置,知道遇到记录过的节点,则结束并返回该节点。
但是这种解法过于麻烦,对于初学者不友好,因此这里我们讲解一个更加巧妙的方法。
思路如下:
如图,我们不妨假设起始节点 A 与环入口 B 之间距离为 L,B 与 第一问中快慢指针相遇点 meet 距离为 X,而整个环的周长为 C。
因为快指针速度为慢指针速度的2倍,所以快指针的路程S1 为慢指针路程 S2 的2倍。
因为慢指针进入环后,在一圈内必定被快指针追上,
所以慢指针路程 S2 = L + X;
同时快指针路程 S1 = L + N*C + X;(N >= 1)
又因为 S1 = 2*S2
所以 2*(L + X) = L + N*C + X;
化简:L = N*C - X.
那么这个公式代表什么意思呢?
即 两个相同的指针,一个从头(即位置A)出发,一个从快慢指针相遇点(即meet位置)出发,他们会在环的入口处相遇!
所以我们就可以写出这样的代码:
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode*fast, *slow;
fast = slow = head;
while(fast && fast->next){
slow = slow->next;
fast = fast->next->next;
//成环
if(fast == slow){
struct ListNode* meet = fast;
while(meet != head){
meet = meet->next;
head = head->next;
}
return head;//meet也一样
}
}
//不成环
return NULL;
}
小伙伴们对链表成环问题了解了吗?了解后不妨亲自写代码实操一下哦~