xamples
epeat
ode
pproach
ptimize
est
Given the head of a singly linked list, determine if there is a cycle within the linked list. If there is a cycle, return true and log the length of the cycle and the first node in the cycle. If there is no cycle, return false.
Here's the catch:
You canNOT use any additional data structures, including modifying the existing data structure. No arrays, no objects, no maps, no linked lists, etc.
The linked list constructor is already provided for you - therefore you canNOT modify the linked list/properties on the node.
Also remember that the nodes in the linked list can have the same values.
function Node (value) {
this.value = value;
this.next = null;
}
function BuildLinkedList (linkedListLength, cycleLength) {
if (cycleLength >= linkedListLength) {
throw new Error('cycleLength must be smaller than linkedListLength');
}
var newNode;
var startNode = new Node(randomNum());
this.head = startNode;
var previous = startNode;
for (var i = 1; i < linkedListLength; i++) {
newNode = new Node(randomNum());
previous.next = newNode;
previous = newNode;
if (i === linkedListLength - cycleLength) {
var startingNodeOfCycle = newNode;
}
}
newNode.next = startingNodeOfCycle;
}
function randomNum() {
return Math.floor(Math.random() * 100) + 1;
}
var linkedList = new BuildLinkedList(6, 3)
where the list starts cycling through
True
Length: 6
Start Node: 3
function detectLoop (linkedList) {
var startNode = linkedList.head
// An empty list has no cycles
if (startNode === null || startNode.next === null) {
return false;
}
var slowNode = startNode,
fastNode = startNode.next;
while(fastNode !== null) {
slowNode = slowNode.next;
if (fastNode.next === null) {
return false;
}
fastNode = fastNode.next.next;
if (slowNode === fastNode) {
console.log(findCycleLength(slowNode),
findStartOfCycle(startNode,findCycleLength(slowNode)))
return true;
}
}
return false;
}
Hints below
function findCycleLength(nodeInCycle) {
var count = 1;
var runner = nodeInCycle.next;
while (runner !== nodeInCycle) {
runner = runner.next;
count++;
}
return count;
}
A solution
Hints below
function findStartOfCycle(startNode, cycleLength) {
var fastNode = startNode,
slowNode = startNode;
for (var i = 0; i < cycleLength; i++) {
fastNode = fastNode.next;
}
while (fastNode !== slowNode) {
fastNode = fastNode.next;
slowNode = slowNode.next;
if (fastNode === slowNode) {
return fastNode;
}
}
}
Solution below
Why does this work?
Why do we start N nodes in to the linked list
(N representing the length of the cycle)?
Well, imagine that you have a first pointer at the head of the LL and a second pointer at the second node. As you increment the pointers one node at a time, they will always be adjacent to each other. Now let's start over, keeping the first pointer at the head, but point the second pointer to the 3rd node. As we increment, this yields a distance of one node between them. Now let's increase the second pointer to the 4th node. As we increment, this yields a distance of two nodes between them. As we continually increase the distance between them, eventually reaching the length of the cycle, as we increase the pointers, we will eventually reach the point where they overlap at the start node of the cycle.