面试题02.08-环路检测,如果用快慢指针来解题,那么本质是一道数学题。
使用快慢指针解题:
-
定义3个变量
- fast:快指针,每次走两步;
- slow:慢指针,每次走一步;
- rs:链表起始的位置;
-
如果链表有“环”那么fast与slow一定会在环里相遇,当fast === null 或者 fast.next === null 那么意味着,改链表没有环;
-
接下来我们求“环”的起点,首先我们先明确的几个点
- fast与slow的相遇永远是fast追上了slow
- 还要记住几个关键位置,“环”的起点,以及fast与slow相遇的位置
-
假设:当slow第一次走到“环”的起点时,需要走 a 步;那么这时候fast就会距离“环”起点 a 的地方,因为fast = 2倍slow;
-
当slow走到“环”的起点时,我们思考,fast什么时候能追上slow?fast是slow的两倍,那么每走一次fast就跟slow近了一步。
-
假设我们fast和slow同时走了X步,使得fast追上了slow,那么fast在“环”里走过的路程为 2x+a,这时候可能很多人会疑惑,算这个有什么用?回过头我们看slow,由于slow每次走了一步,那么这时候slow在环里走了已经x步,然而这时fast刚好在环里走了2x+a的路程,那么2x+a-x 就等于 x+a ,这也就意味着,从“环”的起点开始,每次走一步,走x+a步那么就会再次回到“环”的起点
-
这时候slow已经走了x步了,同时在继续走a步那么就能回到“环”的起始位置。恰好从头部开始往后走a步也能到达“环”的起始位置。
-
有了上述逻辑,那么我们先通过 fast === slow,找到fast与slow在环中相遇的位置,紧接着在使slow往后走,同时让rs从链表的头部开始走,每次走一步,一共走a步,那么他们必然在“环”的起始位置相遇时。
// 上述8中的逻辑,rs从链表头部开始走,slow从环中与fast的相遇点往后走,两个人同时走一步,在a步后必然相遇。 let rs = head while(rs !== slow){ rs = rs.next; slow = slow.next; } return slow
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var detectCycle = function(head) {
let fast = head ;
let slow = head ;
if(head && head.next){
do {
fast = fast.next.next;
slow = slow.next;
} while((fast!==null && fast.next!==null) && (fast !== slow))
if(fast===null || fast.next===null){
return null
}else{
let rs = head
while(rs !== slow){
rs = rs.next;
slow = slow.next;
}
return slow
}
}else{
return null
}
};
\