mirror of
https://github.com/TheAlgorithms/JavaScript.git
synced 2025-07-05 08:16:50 +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:
@ -82,6 +82,7 @@
|
|||||||
* **Linked-List**
|
* **Linked-List**
|
||||||
* [AddTwoNumbers](Data-Structures/Linked-List/AddTwoNumbers.js)
|
* [AddTwoNumbers](Data-Structures/Linked-List/AddTwoNumbers.js)
|
||||||
* [CycleDetection](Data-Structures/Linked-List/CycleDetection.js)
|
* [CycleDetection](Data-Structures/Linked-List/CycleDetection.js)
|
||||||
|
* [CycleDetectionII](Data-Structures/Linked-List/CycleDetectionII.js)
|
||||||
* [DoublyLinkedList](Data-Structures/Linked-List/DoublyLinkedList.js)
|
* [DoublyLinkedList](Data-Structures/Linked-List/DoublyLinkedList.js)
|
||||||
* [MergeTwoSortedLinkedLists](Data-Structures/Linked-List/MergeTwoSortedLinkedLists.js)
|
* [MergeTwoSortedLinkedLists](Data-Structures/Linked-List/MergeTwoSortedLinkedLists.js)
|
||||||
* [ReverseSinglyLinkedList](Data-Structures/Linked-List/ReverseSinglyLinkedList.js)
|
* [ReverseSinglyLinkedList](Data-Structures/Linked-List/ReverseSinglyLinkedList.js)
|
||||||
|
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