Skip to content

Added slow and fast pointers algorithms #14 #424

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,14 @@
* [LinearSearch](https://github.com/TheAlgorithms/Javascript/blob/master/Search/LinearSearch.js)
* [StringSearch](https://github.com/TheAlgorithms/Javascript/blob/master/Search/StringSearch.js)

## Slow and Fast Pointers
* [HasCycle](https://github.com/TheAlgorithms/Javascript/blob/master/Slow-Fast-Pointer/HasLinkedListCycle.js)
* [CycleLength](https://github.com/TheAlgorithms/Javascript/blob/master/Slow-Fast-Pointer/LinkedListCycleLength.js)
* [Middle](https://github.com/TheAlgorithms/Javascript/blob/master/Slow-Fast-Pointer/MiddleOfLinkedList.js)
* [ReArrange](https://github.com/TheAlgorithms/Javascript/blob/master/Slow-Fast-Pointer/ReArrangeLinkedList.js)
* [StartOfCycle](https://github.com/TheAlgorithms/Javascript/blob/master/Slow-Fast-Pointer/StartOfLinkedListCycle.js)
* [IsPalindrome](https://github.com/TheAlgorithms/Javascript/blob/master/Slow-Fast-Pointer/IsLinkedListPalidrome.js)

## Sorts
* [BogoSort](https://github.com/TheAlgorithms/Javascript/blob/master/Sorts/BogoSort.js)
* [BubbleSort](https://github.com/TheAlgorithms/Javascript/blob/master/Sorts/BubbleSort.js)
Expand Down
23 changes: 23 additions & 0 deletions Data-Structures/Linked-List/SinglyLinkList.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ var LinkedList = (function () {
}
// Increment the length
this.length++
return this
}

// Removes the node with the value as param
Expand Down Expand Up @@ -179,6 +180,26 @@ var LinkedList = (function () {
return currentNode.element
}

LinkedList.prototype.addNodeToTail = function (node) {
var tail = this.head
for (var i = 0; i < this.length - 1; i++) {
tail = tail.next
}
tail.next = node
}

LinkedList.prototype.print = function () {
var temp = this.head
var list = []

while (temp !== null) {
list.push(temp.element)
temp = temp.next
}

console.log(list.join('->'))
}

// Function to view the LinkedList
LinkedList.prototype.view = function () {
var currentNode = this.head
Expand Down Expand Up @@ -207,3 +228,5 @@ linklist.addAt(4, 15)
console.log(linklist.indexOf(8))
console.log(linklist.size())
linklist.view()

module.exports = LinkedList
38 changes: 38 additions & 0 deletions Slow-Fast-Pointers/HasLinkedListCycle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// https://en.wikipedia.org/wiki/Cycle_detection

/**
* Checks if there is a cycle in a LinkedList
* @param {LinkedList} head
* @returns {Boolean}
*/
function hasCycle (head) {
let slow = head
let fast = head
let isCircular = false

while (fast !== null && fast.next !== null) {
slow = slow.next
fast = fast.next.next
if (slow === fast) {
isCircular = true
break
}
}

return isCircular
}

const LinkedList = require('../Data-Structures/Linked-List/SinglyLinkList')
const linkedList = new LinkedList()
.add(1)
.add(2)
.add(3)
.add(4)
.add(5)
.add(6)
const { head } = linkedList

console.log('Has Cycle', hasCycle(head)) // false

linkedList.addNodeToTail(head)
console.log('Has Cycle', hasCycle(head)) // true
88 changes: 88 additions & 0 deletions Slow-Fast-Pointers/IsLinkedListPalidrome.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// https://en.wikipedia.org/wiki/Cycle_detection

/**
* Finds the middle of a LinkedList
* @param {LinkedList} head
* @returns {LinkedList}
*/
function middleOfLinkedList (head) {
let slow = head
let fast = head

while (fast !== null && fast.next !== null) {
slow = slow.next
fast = fast.next.next
}

return slow
}

/**
* Reverse the Linked list in place
* @param {LinkedList} current
* @returns {LinkedList}
*/
const reverseLinkedList = (current) => {
let prev = null
let next = null

while (current !== null) {
next = current.next
current.next = prev
prev = current
current = next
}

return prev
}

/**
* Does a palindrome check between two nodes in a linkedList
* @param {LinkedList} first
* @param {LinkedList} second
* @returns {LinkedList}
*/
const compare = (first, second) => {
// Keep copy to reverse in place at the end
const copySecond = second

// Compare the palindrome
while (first !== null && second !== null && first.element === second.element) {
first = first.next
second = second.next
}

// Revert the reverse in place of the second half
reverseLinkedList(copySecond)

return second
}

/**
* Determines if a LinkedList is a palindrome
* @param {LinkedList} head
* @returns {Boolean}
*/
function isLinkedListPalindrome (head) {
if (head === null || head.next === null) return true

const middle = middleOfLinkedList(head)
const secondHalfReversed = reverseLinkedList(middle)
const secondHalf = compare(head, secondHalfReversed)

return (head === null || secondHalf === null)
}

const LinkedList = require('../Data-Structures/Linked-List/SinglyLinkList')
const linkedList = new LinkedList()
.add(1)
.add(2)
.add(3)
.add(2)
.add(1)
const { head } = linkedList

console.log('Is palindrome', isLinkedListPalindrome(head)) // true

linkedList.add(1)
console.log('Is palindrome', isLinkedListPalindrome(head)) // false
59 changes: 59 additions & 0 deletions Slow-Fast-Pointers/LinkedListCycleLength.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// https://en.wikipedia.org/wiki/Cycle_detection

/**
* Counts the length of the cycle
* @param {LinkedList} slow
* @returns {Number}
*/
const calculateCycleLength = (slow) => {
let current = slow
let cycleLength = 0

while (true) {
current = current.next
cycleLength++

if (current === slow) break
}

return cycleLength
}

/**
* Determines the length of the cycle in the LinkedList
* @param {LinkedList} head
* @returns {Number}
*/
function cycleLength (head) {
let slow = head
let fast = head
let length = 0

while (fast !== null && fast.next !== null) {
slow = slow.next
fast = fast.next.next

if (slow === fast) {
length = calculateCycleLength(slow)
break
}
}

return length
}

const LinkedList = require('../Data-Structures/Linked-List/SinglyLinkList')
const linkedList = new LinkedList()
.add(1)
.add(2)
.add(3)
.add(4)
.add(5)
.add(6)
const { head } = linkedList

linkedList.addNodeToTail(head.next.next)
console.log('Cycle length', cycleLength(head)) // 4

linkedList.addNodeToTail(head.next.next.next)
console.log('Cycle length', cycleLength(head)) // 3
29 changes: 29 additions & 0 deletions Slow-Fast-Pointers/MiddleOfLinkedList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// https://en.wikipedia.org/wiki/Cycle_detection

/**
* Finds the middle of a LinkedList
* @param {LinkedList} head
* @returns {LinkedList}
*/
function middleOfLinkedList (head) {
let slow = head
let fast = head

while (fast !== null && fast.next !== null) {
slow = slow.next
fast = fast.next.next
}

return slow
}

const LinkedList = require('../Data-Structures/Linked-List/SinglyLinkList')
const linkedList = new LinkedList()
.add(1)
.add(2)
.add(3)
.add(4)
.add(5)
const { head } = linkedList

console.log('Middle', middleOfLinkedList(head).element) // 3
1 change: 1 addition & 0 deletions Slow-Fast-Pointers/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Slow Fast Pointers
82 changes: 82 additions & 0 deletions Slow-Fast-Pointers/ReArrangeLinkedList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// https://en.wikipedia.org/wiki/Cycle_detection

/**
* Finds the middle of a LinkedList
* @param {LinkedList} head
* @returns {LinkedList}
*/
const middleOfLinkedList = (head) => {
let slow = head
let fast = head

while (fast !== null && fast.next !== null) {
fast = fast.next.next
slow = slow.next
}

return slow
}

/**
* Reverse the Linked list in place
* @param {LinkedList} current
* @returns {LinkedList}
*/
const reverseLinkedList = (current) => {
let prev = null
let next = null

while (current !== null) {
next = current.next
current.next = prev
prev = current
current = next
}

return prev
}

/**
* Merges the two LinkedList by alternating between the two
* @param {LinkedList} first
* @param {LinkedList} second
* @returns {LinkedList}
*/
const merge = (first, second) => {
while (first !== null && second !== null) {
let next = first.next
first.next = second
first = next

next = second.next
second.next = first
second = next
}

if (first !== null) first.next = null
}

/**
* Rearranges the LinkedList in place by reversing the second half and merging the list back by alternating the values
* @param {LinkedList} head
*/
const reArrange = function (head) {
const middle = middleOfLinkedList(head)
const secondHalfReversed = reverseLinkedList(middle)

merge(head, secondHalfReversed)
}

const LinkedList = require('../Data-Structures/Linked-List/SinglyLinkList')
const linkedList = new LinkedList()
.add(1)
.add(2)
.add(3)
.add(4)
.add(5)
.add(6)
const { head } = linkedList

linkedList.print() // 1->2->3->4->5->6
reArrange(head)
linkedList.print() // 1->6->2->5->3->4
Loading