题目如下:
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
工具代码
链表节点
class ListNode{
public $val = null;
/**
* @var ListNode $next
*/
public $next = null;
function __construct($val = 0) {
$this->val = $val;
$this->next = null;
}
}
空白方法
/**
* Definition for a singly-linked list.
* class ListNode {
* public $val = 0;
* public $next = null;
* function __construct($val) { $this->val = $val; }
* }
*/
class Solution {
/**
* @param ListNode $head
* @return ListNode
*/
function detectCycle($head) {
}
}
思路
快慢指针$slow同时出发,快指针$faster一次走两步, $slow一次走一步. 设在
M
M
M点相遇时$slow走了
S
S
S步. 则快指针$faster走了
2
S
2S
2S步.
快指针$faster先走了
S
S
S步到相遇点然后在圈里绕了
S
S
S步. 相遇则有环(如果是无环则$faster会先跑到尽头)
问个zz问题, 不想看的话请调到下一张图的位置
就在就在$slow和$fast相遇时, 有两个$sleepSlow $sleepFast分别以与$slow $fast相同的速度 同时从起点出发(跟风), 那么它们会相遇吗?
$slow和$fast继续以不变的速度绕圈四个指针有可能同时相遇吗? 相遇的点是哪里?
S
S
S和
2
S
2S
2S步步都会在
M
M
M点, 那么
3
S
3S
3S步
4
S
4S
4S步呢?
当然都是在
M
M
M点
$sleepSlow和$sleepFast在初次相遇时分别走了
S
S
S步和
2
S
2S
2S步. 花了N长时间
$slow和$fast分别走了
2
S
2S
2S步和
4
S
4S
4S步, 也回到了
M
M
M点. 花了2N长的时间.
那么请问$slow和$sleepSlow速度都相同, 而且会在
M
M
M点相遇, 请问它们第一次在哪里相遇.
有个美女以一定速度在操场绕圈, 你看费尽心思 准时机以同样的速度从入口冲进去和他一起跑. 那么请问你们第一次相遇时哪个点?当然是入口啊
把图画成这样肯定是因为我不在乎他们分别走了多少圈, 肯定不是我没法画得好看[狗头]
这里别人有画好看的图 .我就不剽窃了 https://mp.weixin.qq.com/s/Nh6jxQtO-xOT_WuX-B5w3Q
代码
/**
* @param ListNode $head
* @return ListNode
*/
function detectCycle($head) {
if (!$head){
return null;
//空的
}
$sleepFastS = $sleepSlowS = $fastS = $slowS = 0;
$sleepFast = $sleepSlow = $slow = $fast = $head;
while (true){
if (!$fast = $fast->next){
return null;
//无环
}
if (!$fast = $fast->next){
return null;
//无环
}
$slow = $slow->next;
$slowS += 1;
$fastS += 2;
if ($slow === $fast){
break;
//相遇则有环
//设$slow走了S步,
//那么$fast走了2S步
}
}
$res = $head;
//在$fast和$slow初次相遇时 $sleepSlow $sleepFast出发
//四个指针必定同时到达 $fast和$slow初次相遇的点
while (true){
$sleepFast = $sleepFast->next->next;
$fast = $fast->next->next;
$sleepSlow = $sleepSlow->next;
$slow = $slow->next;
$sleepSlowS += 1;
$sleepFastS += 2;
$slowS += 1;
$fastS += 2;
if ($sleepSlow === $slow){
$res = $slow;//时机
}
if ($sleepFast === $sleepSlow){//四目相对
break;
// $sleepSlow $sleepFast 走的路程 和前一个循环$slow $fast走的一模一样
// 现在$sleepSlow走了S步,
// 那么$sleepFast走了2S步,
// $slow走了2S步,
// $fast走了4S步
}
}
return $res;
}
简化代码
/**
* @param ListNode $head
* @return ListNode
*/
function detectCycle($head) {
if (!$head){
return null;
}
$slow = $fast = $head;
while (true){
if (!$fast = $fast->next){
return null;
}
if (!$fast = $fast->next){
return null;
//无环
}
$slow = $slow->next;
if ($slow === $fast){
break;
}
}
$sleepSlow = $head;
while ($sleepSlow !== $slow){
$sleepSlow = $sleepSlow->next->next;
$slow = $slow->next;
}
return $slow;
}