diff --git a/README.md b/README.md index 665bc09c..fd888d40 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ Collection of interview questions with Unit Tests. Problems includes Data Struct - [Remove Consecutive Repeated Digits](src/_DataStructures_/Stack/remove-consecutive-repeated-digits) - [Implement 2 Stacks using Single Array](src/_DataStructures_/Stack/2-stacks-using1-array) + - [Queue](src/_DataStructures_/Queue) - [Weave](src/_DataStructures_/Queue/weave) @@ -37,7 +38,12 @@ Collection of interview questions with Unit Tests. Problems includes Data Struct - [Doubly Linked List](src/_DataStructures_/DoublyLinkedList) - [Trees](src/_DataStructures_/Trees) - - [Binary Search Tree](src/_DataStructures_/Trees/BST) + - [Binary Search Tree](src/_DataStructures_/Trees/BinarySearchTree) + - [Find kth maximum in a BinarySearchTree](src/_DataStructures_/Trees/BinarySearchTree/find-kth-max) + - [Find kth minimum in a BinarySearchTree](src/_DataStructures_/Trees/BinarySearchTree/find-kth-min) + - [Find Ancestors of a Node](src/_DataStructures_/Trees/BinarySearchTree/find-ancestors) + - [Find Height of BST](src/_DataStructures_/Trees/BinarySearchTree/height-of-bst) + - [Find k Nodes from Root of BST](src/_DataStructures_/Trees/BinarySearchTree/find-k-nodes-from-root) - [Suffix Tree](src/_DataStructures_/SuffixTree) ### Logical Problems @@ -50,7 +56,7 @@ Collection of interview questions with Unit Tests. Problems includes Data Struct - [FizzBuzz](src/_Problems_/fizzbuzz) - [String Permutaions](src/_Problems_/get-string-permutations) - [Get Subsequence](src/_Problems_/get_subsequence) -- [Get Maze Path](src/_Problems_/get_subsequence) +- [Get Maze Path](src/_Problems_/get-mazePath) - [Get longest consecutive 1s](src/_Problems_/max-consecutive-1s) - [Get Max Char](src/_Problems_/maxchar) - [Get Smallest Common Number](src/_Problems_/get-smallest-common-number) diff --git a/src/_Classics_/fibonacci/index.js b/src/_Classics_/fibonacci/index.js index 6c61bdc1..979fb5c8 100644 --- a/src/_Classics_/fibonacci/index.js +++ b/src/_Classics_/fibonacci/index.js @@ -2,8 +2,10 @@ // the algorithm has time complexity of O(n^2), very bad! function fibonacci(position) { // if position is 1 or 2, the number in fibonacci sequence will be 1 - if (position <= 1) { + if (position === 1 || position === 0) { return position; + } else if (position < 0) { + throw new Error('Invalid Position'); } // else the element in fibonacci sequence will be the sum of @@ -26,8 +28,11 @@ function fibonacciMemoized(index, cache) { if (cache[index]) { return cache[index]; } else { - if (index <=1) { + if (index === 1 || index === 0) { return index; + } else if (index < 0) { + throw new Error('Invalid Position'); + } else { cache[index] = fibonacciMemoized(index - 1, cache) + @@ -43,8 +48,10 @@ function fibonacciMemoized(index, cache) { function fibonacciTabular(n) { const table = [0, 1]; - if (n <= 1) { + if (n === 1 || n === 0) { return n; + } else if (n < 0) { + throw new Error('Invalid Position'); } for (let i = 2; i <= n; i += 1) { table[i] = table[i - 1] + table[i - 2]; diff --git a/src/_DataStructures_/DoublyLinkedList/index.js b/src/_DataStructures_/DoublyLinkedList/index.js index 522924b9..40d6bf3e 100644 --- a/src/_DataStructures_/DoublyLinkedList/index.js +++ b/src/_DataStructures_/DoublyLinkedList/index.js @@ -55,10 +55,12 @@ class DoublyLinkedList { display() { let address = this.head.next; + let addresses = [] while (address !== this.tail) { - console.log(address.data); + addresses.push(address.data) address = address.next; } + return addresses } } diff --git a/src/_DataStructures_/Queue/index.js b/src/_DataStructures_/Queue/index.js index 99d1861c..d51bcab0 100644 --- a/src/_DataStructures_/Queue/index.js +++ b/src/_DataStructures_/Queue/index.js @@ -17,4 +17,4 @@ class Queue { } } -module.exports = Queue; +module.exports = Queue; \ No newline at end of file diff --git a/src/_DataStructures_/Stack/postfix-expression-evaluation/index.js b/src/_DataStructures_/Stack/postfix-expression-evaluation/index.js index 3441abb5..9db393e9 100644 --- a/src/_DataStructures_/Stack/postfix-expression-evaluation/index.js +++ b/src/_DataStructures_/Stack/postfix-expression-evaluation/index.js @@ -15,9 +15,9 @@ function evaluatePostfixExpression(expression) { s.push(Number(char)); } else { // if char is an operator then pop two elements from stack, evaluate them accordingly based on operator. - //push the result to stack + //push the result to stack let val1 = s.pop(); - let val2 = s.pop() + let val2 = s.pop(); switch (char) { case '+': s.push(val2 + val1); @@ -38,3 +38,7 @@ function evaluatePostfixExpression(expression) { //pop the value of postfix expression return s.pop(); } + +module.exports = { + evaluatePostfixExpression, +}; diff --git a/src/_DataStructures_/Stack/postfix-expression-evaluation/postfix-expression-evaluation.test.js b/src/_DataStructures_/Stack/postfix-expression-evaluation/postfix-expression-evaluation.test.js new file mode 100644 index 00000000..47e0de42 --- /dev/null +++ b/src/_DataStructures_/Stack/postfix-expression-evaluation/postfix-expression-evaluation.test.js @@ -0,0 +1,55 @@ +const { evaluatePostfixExpression } = require('.'); + +describe('Postfix expression evaluation', function () { + it('should be a function', function () { + expect(typeof evaluatePostfixExpression).toEqual('function'); + }); + + it('should return a number', function () { + const expression = '11+'; + + expect(typeof evaluatePostfixExpression(expression)).toEqual('number') + }); + + it('should handle addition', function () { + const expression = '23+'; + const expected = 5; + + expect(evaluatePostfixExpression(expression)).toEqual(expected); + }); + + it('should handle subtraction', function () { + const expression = '54-'; + const expected = 1; + + expect(evaluatePostfixExpression(expression)).toEqual(expected); + }); + + it('should handle multiplication', function () { + const expression = '34*'; + const expected = 12; + + expect(evaluatePostfixExpression(expression)).toEqual(expected); + }); + + it('should handle division', function () { + const expression = '62/'; + const expected = 3; + + expect(evaluatePostfixExpression(expression)).toEqual(expected); + }); + + it('should handle negative numbers', function () { + const expression = '25-'; + const expected = -3; + + expect(evaluatePostfixExpression(expression)).toEqual(expected); + }); + + it('should handle multiple operators', function () { + const expression = '123*+'; + const expected = 7; + + expect(evaluatePostfixExpression(expression)).toEqual(expected); + }); +}); diff --git a/src/_DataStructures_/Trees/BST/Node.js b/src/_DataStructures_/Trees/BinarySearchTree/Node.js similarity index 100% rename from src/_DataStructures_/Trees/BST/Node.js rename to src/_DataStructures_/Trees/BinarySearchTree/Node.js diff --git a/src/_DataStructures_/Trees/BinarySearchTree/find-ancestors/index.js b/src/_DataStructures_/Trees/BinarySearchTree/find-ancestors/index.js new file mode 100644 index 00000000..4ccea5f9 --- /dev/null +++ b/src/_DataStructures_/Trees/BinarySearchTree/find-ancestors/index.js @@ -0,0 +1,49 @@ +// eslint-disable-next-line no-unused-vars +const BST = require('../index'); + +/** You should go through this conversation here: + * https://github.com/knaxus/problem-solving-javascript/pull/63 + */ + +function findAncestors(root, value) { + /** + * search the given node and meanwhile + * keep pushing the visited nodes + */ + if (root === null) return false; + + if (value < root.value) { + const left = findAncestors(root.leftChild, value); + if (left) { + return [...left, root.value]; + } + return false; + } + + if (value > root.value) { + const right = findAncestors(root.rightChild, value); + if (right) { + return [...right, root.value]; + } + return false; + } + + if (value === root.value) return []; + return false; +} + +// create a BST +// const myBST = new BST(6); +// myBST.add(4); +// myBST.add(9); +// myBST.add(2); +// myBST.add(5); +// myBST.add(14); +// myBST.add(8); +// myBST.add(12); +// myBST.add(10); + +// console.log(findAncestors(myBST.root, 10)); +// console.log(findAncestors(myBST.root, 101)); + +module.exports = findAncestors; diff --git a/src/_DataStructures_/Trees/BinarySearchTree/find-k-nodes-from-root/index.js b/src/_DataStructures_/Trees/BinarySearchTree/find-k-nodes-from-root/index.js new file mode 100644 index 00000000..25aa70d1 --- /dev/null +++ b/src/_DataStructures_/Trees/BinarySearchTree/find-k-nodes-from-root/index.js @@ -0,0 +1,33 @@ +// eslint-disable-next-line no-unused-vars +const BST = require('../index'); + +function findKNodes(root, k) { + let arr = []; + + if (root === null) return []; + if (k === 0) return [...arr, root.value]; + + const left = findKNodes(root.leftChild, k - 1); + arr = [...arr, ...left]; + + const right = findKNodes(root.rightChild, k - 1); + arr = [...arr, ...right]; + return arr; +} + +// create a BST +// const myBST = new BST(6); + +// myBST.add(2); +// myBST.add(19); +// myBST.add(14); +// myBST.add(8); +// myBST.add(5); +// myBST.add(12); +// myBST.add(33); +// myBST.add(52); +// myBST.add(1); + +// console.log(findKNodes(myBST.root, 2)); + +module.exports = findKNodes; diff --git a/src/_DataStructures_/Trees/BinarySearchTree/find-kth-max/index.js b/src/_DataStructures_/Trees/BinarySearchTree/find-kth-max/index.js new file mode 100644 index 00000000..21ba18f7 --- /dev/null +++ b/src/_DataStructures_/Trees/BinarySearchTree/find-kth-max/index.js @@ -0,0 +1,39 @@ +// eslint-disable-next-line no-unused-vars +const BST = require('../index'); + +// Inorder traversal returns a sorted array +function inOrderTraversal(root) { + if (root === null) return []; + let arr = []; + // traverse left + const left = inOrderTraversal(root.leftChild); + arr = [...left, root.value]; + const right = inOrderTraversal(root.rightChild); + return [...arr, ...right]; +} + +function findKthMax(rootNode, k) { + const arr = inOrderTraversal(rootNode); + if (k <= 0 || k > arr.lenth) { + throw new Error('Invalid value for K'); + } + return arr[arr.length - k]; +} + +// // create a BST +// const myBST = new BST(6); + +// myBST.add(2); +// myBST.add(19); +// myBST.add(14); +// myBST.add(8); +// myBST.add(5); +// myBST.add(12); +// myBST.add(33); +// myBST.add(52); +// myBST.add(1); + +// // find 3rd max +// console.log(findKthMax(myBST.root, 3)); + +module.exports = findKthMax; diff --git a/src/_DataStructures_/Trees/BinarySearchTree/find-kth-min/index.js b/src/_DataStructures_/Trees/BinarySearchTree/find-kth-min/index.js new file mode 100644 index 00000000..ad18cdea --- /dev/null +++ b/src/_DataStructures_/Trees/BinarySearchTree/find-kth-min/index.js @@ -0,0 +1,39 @@ +// eslint-disable-next-line no-unused-vars +const BST = require('../index'); + +// Inorder traversal returns a sorted array +function inOrderTraversal(root) { + if (root === null) return []; + let arr = []; + // traverse left + const left = inOrderTraversal(root.leftChild); + arr = [...left, root.value]; + const right = inOrderTraversal(root.rightChild); + return [...arr, ...right]; +} + +function findKthMin(rootNode, k) { + const arr = inOrderTraversal(rootNode); + if (k <= 0 || k > arr.lenth) { + throw new Error('Invalid value for K'); + } + return arr[k - 1]; +} + +// // create a BST +// const myBST = new BST(6); + +// myBST.add(2); +// myBST.add(19); +// myBST.add(14); +// myBST.add(8); +// myBST.add(5); +// myBST.add(12); +// myBST.add(33); +// myBST.add(52); +// myBST.add(1); +// myBST.add(0); + +// console.log(findKthMin(myBST.root, 3)); + +module.exports = findKthMin; diff --git a/src/_DataStructures_/Trees/BinarySearchTree/height-of-bst/index.js b/src/_DataStructures_/Trees/BinarySearchTree/height-of-bst/index.js new file mode 100644 index 00000000..ad4f1ee7 --- /dev/null +++ b/src/_DataStructures_/Trees/BinarySearchTree/height-of-bst/index.js @@ -0,0 +1,33 @@ +// eslint-disable-next-line no-unused-vars +const BST = require('../index'); + +function findHeightOfBST(root) { + let leftHeight = 0; + let rightHeight = 0; + + if (root === null) return 0; + leftHeight = findHeightOfBST(root.leftChild); + rightHeight = findHeightOfBST(root.rightChild); + + if (leftHeight > rightHeight) { + return leftHeight + 1; + } + return rightHeight + 1; +} + +// create a BST +// const myBST = new BST(6); +// myBST.add(4); +// myBST.add(9); +// myBST.add(2); +// myBST.add(5); +// myBST.add(14); +// myBST.add(8); +// myBST.add(12); +// myBST.add(10); + +// // console.log(myBST.root); +// console.log(myBST.traversePreorder()); +// console.log(findHeightOfBST(myBST.root)); + +module.exports = findHeightOfBST; diff --git a/src/_DataStructures_/Trees/BST/index.js b/src/_DataStructures_/Trees/BinarySearchTree/index.js similarity index 100% rename from src/_DataStructures_/Trees/BST/index.js rename to src/_DataStructures_/Trees/BinarySearchTree/index.js diff --git a/src/_Problems_/get-mazePath/get-mazePath.test.js b/src/_Problems_/get-mazePath/get-mazePath.test.js new file mode 100644 index 00000000..b30f50af --- /dev/null +++ b/src/_Problems_/get-mazePath/get-mazePath.test.js @@ -0,0 +1,41 @@ +const { getMazePath } = require('.'); + +describe('Get maze path', () => { + it('returns all possible solutions for a 2x2 grid', () => { + const expectedSolutions = ['HHVV', 'HVHV', 'HVVH', 'VHHV', 'VHVH', 'VVHH']; + + expect(getMazePath(0, 0, 2, 2)).toEqual(expectedSolutions); + }); + + it('returns an even amount of horizontal and vertical movements', () => { + const solutions = getMazePath(0, 0, 3, 3); + + solutions.forEach(solution => { + expect(solution.length).toEqual(6); + + expect(solution.match(/H/g).length).toEqual(3); + expect(solution.match(/V/g).length).toEqual(3); + }); + }); + + it('returns the expected number of solutions based on given grids', () => { + expect(getMazePath(0, 0, 1, 1).length).toEqual(2); + expect(getMazePath(0, 0, 2, 2).length).toEqual(6); + expect(getMazePath(0, 0, 3, 3).length).toEqual(20); + expect(getMazePath(0, 0, 4, 4).length).toEqual(70); + + expect(getMazePath(1, 1, 4, 4).length).toEqual(20); + }); + + it('returns an empty array when the start and end coordinates are equal', () => { + const solutions = getMazePath(2, 2, 2, 2); + + expect(solutions).toEqual(['']); + }); + + it('returns an empty array when the start coordinates are greater than the end coordinates', () => { + const solutions = getMazePath(2, 2, 1, 1); + + expect(solutions).toEqual([]); + }); +}); \ No newline at end of file diff --git a/src/_Problems_/get-mazePath/index.js b/src/_Problems_/get-mazePath/index.js index 99aead53..cff29bee 100644 --- a/src/_Problems_/get-mazePath/index.js +++ b/src/_Problems_/get-mazePath/index.js @@ -7,10 +7,7 @@ // --->> er = end row // --->> ec = end column - - - -let getMazePath = (cr, cc, er, ec) => { +const getMazePath = (cr, cc, er, ec) => { if(cr == er && cc == ec) { //============POSITIVE BASE CASE=========== let br = []; br.push(''); @@ -37,6 +34,4 @@ let getMazePath = (cr, cc, er, ec) => { return myResult; } - -let path = getMazePath(0, 0, 2, 2); -console.log(path); \ No newline at end of file +module.exports = { getMazePath }; \ No newline at end of file