mirror of
https://github.com/TheAlgorithms/JavaScript.git
synced 2025-07-05 00:01:37 +08:00
implemented CycleDetectionII code in LinkedList (#1482)
* implemented CycleTectionII code * changes made per review by appgurueu * made the changes per review by appgurueu * changes made per review by appgurueu * did some changes * fixed the test file with prettier * Simplify code, renames for clarity --------- Co-authored-by: Lars Mueller <appgurulars@gmx.de>
This commit is contained in:
57
Data-Structures/Linked-List/CycleDetectionII.js
Normal file
57
Data-Structures/Linked-List/CycleDetectionII.js
Normal file
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* A LinkedList based solution for finding the starting node of the cycle in a list.
|
||||
* @returns the node where cycle begins in the linked list. If there is no cycle present, returns null.
|
||||
* @see https://en.wikipedia.org/wiki/Cycle_detection
|
||||
* @see https://leetcode.com/problems/linked-list-cycle-ii/
|
||||
*/
|
||||
|
||||
function findCycleStart(head) {
|
||||
let length = 0
|
||||
let fast = head
|
||||
let slow = head
|
||||
|
||||
while (fast !== null && fast.next !== null) {
|
||||
fast = fast.next.next
|
||||
slow = slow.next
|
||||
if (fast === slow) {
|
||||
length = cycleLength(slow)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (length === 0) {
|
||||
// If there is no cycle, return null.
|
||||
return null
|
||||
}
|
||||
|
||||
let ahead = head
|
||||
let behind = head
|
||||
// Move slow pointer ahead 'length' of cycle times
|
||||
while (length > 0) {
|
||||
ahead = ahead.next
|
||||
length--
|
||||
}
|
||||
|
||||
// Now move both pointers until they meet - this will be the start of cycle
|
||||
while (ahead !== behind) {
|
||||
ahead = ahead.next
|
||||
behind = behind.next
|
||||
}
|
||||
|
||||
// return the meeting node
|
||||
return ahead
|
||||
}
|
||||
|
||||
// head is a node on a cycle
|
||||
function cycleLength(head) {
|
||||
// How long until we visit head again?
|
||||
let cur = head
|
||||
let len = 0
|
||||
do {
|
||||
cur = cur.next
|
||||
len++
|
||||
} while (cur != head)
|
||||
return len
|
||||
}
|
||||
|
||||
export { findCycleStart }
|
39
Data-Structures/Linked-List/test/CycleDetectionII.test.js
Normal file
39
Data-Structures/Linked-List/test/CycleDetectionII.test.js
Normal file
@ -0,0 +1,39 @@
|
||||
import { findCycleStart } from '../CycleDetectionII'
|
||||
import { Node } from '../SinglyLinkedList'
|
||||
|
||||
describe('Detect Cycle', () => {
|
||||
it('no cycle', () => {
|
||||
const head = new Node(1)
|
||||
head.next = new Node(2)
|
||||
|
||||
expect(findCycleStart(head)).toBeNull()
|
||||
})
|
||||
|
||||
it('simple cycle', () => {
|
||||
const head = new Node(1)
|
||||
head.next = new Node(2)
|
||||
head.next.next = new Node(3)
|
||||
head.next.next.next = head.next // Creates a cycle
|
||||
|
||||
expect(findCycleStart(head)).toBe(head.next)
|
||||
})
|
||||
|
||||
it('long list with cycle', () => {
|
||||
const head = new Node(1)
|
||||
head.next = new Node(2)
|
||||
head.next.next = new Node(3)
|
||||
head.next.next.next = new Node(4)
|
||||
head.next.next.next.next = new Node(5)
|
||||
head.next.next.next.next.next = head.next.next // Cycle
|
||||
|
||||
expect(findCycleStart(head)).toBe(head.next.next)
|
||||
})
|
||||
|
||||
it('cycle on last node', () => {
|
||||
const head = new Node(1)
|
||||
head.next = new Node(2)
|
||||
head.next.next = head
|
||||
|
||||
expect(findCycleStart(head)).toBe(head)
|
||||
})
|
||||
})
|
Reference in New Issue
Block a user