diff --git a/src/algorithms/linked-list/cycle/__tests__/cycle.test.js b/src/algorithms/linked-list/cycle/__tests__/cycle.test.js new file mode 100644 index 0000000000..da76bc14c7 --- /dev/null +++ b/src/algorithms/linked-list/cycle/__tests__/cycle.test.js @@ -0,0 +1,50 @@ +import LinkedList from '../../../../data-structures/linked-list/LinkedList'; +import createCycle from '../createCycle'; +import detectCycle from '../detectCycle'; + +describe('Linked List Cycle Tests', () => { + let list; + + beforeEach(() => { + list = new LinkedList(); + }); + + test('detectCycle returns false on list with no cycle', () => { + list + .append(1) + .append(9) + .append(87) + .append(5) + .append(22); + expect(detectCycle(list)).toBe(false); + }); + + test('createCycle creates a cycle and detectCycle detects it', () => { + list + .append(1) + .append(9) + .append(87) + .append(5) + .append(22); + createCycle(list, 2); // Creates cycle linking tail to node at index 2 (value 87) + expect(detectCycle(list)).toBe(true); + }); + + test('createCycle with invalid position does not create cycle', () => { + list + .append(1) + .append(9) + .append(87); + createCycle(list, 10); // Invalid index, no cycle should be created + expect(detectCycle(list)).toBe(false); + }); + + test('createCycle with position -1 does not create cycle', () => { + list + .append(1) + .append(9) + .append(87); + createCycle(list, -1); // No cycle created + expect(detectCycle(list)).toBe(false); + }); +}); diff --git a/src/algorithms/linked-list/cycle/createCycle.js b/src/algorithms/linked-list/cycle/createCycle.js new file mode 100644 index 0000000000..88d43120db --- /dev/null +++ b/src/algorithms/linked-list/cycle/createCycle.js @@ -0,0 +1,24 @@ +export default function createCycle(linkedList, position) { + if (!linkedList.head || position < 0) return; + + let cycleNode = null; + let tail = linkedList.head; + let index = 0; + + while (tail.next) { + if (index === position) { + cycleNode = tail; + } + tail = tail.next; + index += 1; + } + + // For the last node + if (index === position) { + cycleNode = tail; + } + + if (cycleNode) { + tail.next = cycleNode; + } +} diff --git a/src/algorithms/linked-list/cycle/detectCycle.js b/src/algorithms/linked-list/cycle/detectCycle.js new file mode 100644 index 0000000000..e45a34729d --- /dev/null +++ b/src/algorithms/linked-list/cycle/detectCycle.js @@ -0,0 +1,15 @@ +export default function detectCycle(linkedList) { + let slow = linkedList.head; + let fast = linkedList.head; + + while (fast && fast.next) { + slow = slow.next; + fast = fast.next.next; + + if (slow === fast) { + return true; + } + } + + return false; +} diff --git a/src/algorithms/sets/permutations/README.md b/src/algorithms/sets/permutations/README.md index 4b6a268adc..85d72692d5 100644 --- a/src/algorithms/sets/permutations/README.md +++ b/src/algorithms/sets/permutations/README.md @@ -29,7 +29,7 @@ n * (n-1) * (n -2) * ... * 1 = n! When repetition is allowed we have permutations with repetitions. For example the the lock below: it could be `333`. -![Permutation Lock](https://www.mathsisfun.com/combinatorics/images/combination-lock.jpg) +![Permutation Lock](./images/permutations-lock.png) **Number of combinations** diff --git a/src/algorithms/sets/permutations/images/permutations-lock.png b/src/algorithms/sets/permutations/images/permutations-lock.png new file mode 100644 index 0000000000..91d137aa6e Binary files /dev/null and b/src/algorithms/sets/permutations/images/permutations-lock.png differ