环形链表练习
需求1:
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。
var hasCycle = function (head) {
// 判断传入的值,是否为空,为空返回false
if (!head) return false;
// 定义两个值cur、pre
let cur = head, pre = head;
// 判断,当cur及cur的下一指针所指节点都不为空时,往前走,cur往前走一步,pre往前走两步,当cur与pre再次相同,则形成环形链表
while (cur && cur.next) {
cur = cur.next;
pre = pre.next.next;
if (cur === pre) {
// 当cur与pre相同,则指针所指的节点为同一个节点,此链表为环形链表,返回true
return true
}
}
// 跳出循环,则表示已循环结束,最终cur都不等同pre,不存在环形链表,返回false
return false;
};
需求2:
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
var hasCycle = function (head) {
// 判断传入的值,是否为空,为空返回false
if (!head) return false;
// 定义两个值cur、pre
let cur = head, pre = head;
// 判断,当cur及cur的下一指针所指节点都不为空时,往前走,cur往前走一步,pre往前走两步,当cur与pre再次相同,则形成环形链表
while (cur && cur.next) {
cur = cur.next;
pre = pre.next.next;
if (cur === pre) {
// 当cur与pre相同,则指针所指的节点为同一个节点,此链表为环形链表,再次循环
let temp = head;
// 当两值不相等时,继续往下面走
while (temp !== pre) {
temp = temp.next;
pre = pre.next;
}
// 两值相等后,进行return
return temp
}
}
// 跳出循环,则表示已循环结束,最终cur都不等同pre,不存在环形链表,返回false
return false;
};
需求2的解题思路如下:
// A -> B -> C -> D -> E -> F
// ↑ ↓
// J <- I <- H <- G
// 假设有两个指针pre和cur
// pre 一步走一格
// cur 一步走两格
// 从A出发,会在I处相遇
// pre、cur共同走过的路程:A+B+C(设为路程A)
// 从C开始,pre走的路程:D+E+F+G+H+I(设为路程B)
// 从C开始,pre在闭环中还未走的路程:J+C(设为路程C)
// 从C开始,cur走的路程:N(C+D+E+F+G+H+I+J)+pre走的路程(D+E+F+G+H+I):N(路程B+路程C)+路程B
// 由上所得:
// pre所走的全路程:路程A+路程B
// cur所走的全路程:路程A+N(路程B+路程C)+路程B
// 因为pre的速度是cur速度的一半
// 所以:2(A+B)=A+N(B+C)+B
// 简化得:A=NC+(N-1)B -> A=(N-1)(B+C)-C -> A = C
// 得到以上公式,可得知,从cur,pre相遇时,再创建一个指针temp,从索引头开始与pre同时走,相遇的时候,就是链表开始入环的第一个节点