题目要求:给定一个链表的头结点,判断链表中是否有环+找到环形入口 【力扣141 142】
方法0:flag标志
遍历结点并标志node.flag=1,如果遇到结点已标志过,说明链表中有环。
环形入口:遇到的第一个node.flag=1的结点
var hasCycle = function(head) {
let temp=head;
while(temp){
if(temp.flag) return true;//return temp
else{
temp.flag=1;
temp=temp.next;
}
}
return false;//return null;
};
方法1:哈希表
当题目要求不能修改链表时,方法0不能使用。与方法0同样的思想,即遍历判断结点是否访问过,可以用哈希表来实现。
环形入口:第一个满足mySet.has(node)===1的结点
var detectCycle = function(head) {
let mySet=new Set();
let temp=head;
while(temp){
if(mySet.has(temp)) return true;
else{
mySet.add(temp);
temp=temp.next;
}
}
return false;
};
方法2:快慢指针
快指针fast每次移动两个结点,慢指针slow每次移动一个结点,如果链表中存在环,快慢指针一定会相遇。
var detectCycle = function(head) {
if(head===null) return false;
let slow=head;
let fast=head;
while(fast.next&&fast.next.next){
fast=fast.next.next;
slow=slow.next;
if(fast===slow) return true;
}
return false;
};
环形入口:
设head到环形入口的距离为a,环形部分的长度为b,相遇时快慢指针走过的距离分别为f、s。有:
f=s+nb(快指针比慢指针多走了n圈)
f=2s(slow走一步fast走两步)
因此s=nb。
而slow到环形入口需要移动a+nb,即相遇时slow需要移动a即可到达环形入口。
a未知,但head到环形入口的距离也是a,因此slow和head同时移动必将相遇于环形入口。
var detectCycle = function(head) {
if(head===null) return null;
let slow=head;
let fast=head;
while(fast.next&&fast.next.next){
fast=fast.next.next;
slow=slow.next;
if(fast===slow){
while(head&&slow){
if(head==slow) return slow;
head=head.next;
slow=slow.next;
}
}
}
return null;
};