├── Chapter1 ├── 1.1-StringUniqueChars.js ├── 1.2-StringAnagrams.js ├── 1.3-StringWhiteSpace.js ├── 1.4-StringCompression.js └── 1.8-StringRotation.js ├── Chapter2-LinkedLists ├── 2.1-RemoveDups.js ├── 2.2-KthLastElement.js ├── 2.3-DeleteFromLinkedList.js └── 2.4-PartitionLL.js ├── Chapter3-StacksandQueues ├── 3.2-StackMinimum.js ├── 3.3-SetOfStacks.js ├── 3.5-QueueTwoStacks.js └── 3.6-SortedStack.js ├── Chapter8-Recursion ├── 8.1-Fibonacci.js ├── 8.2-GridPaths.js ├── 8.4-StringPermutations.js └── 8.5-ValidParenthesesCombos.js ├── DataStructures ├── BinarySearchTree.js ├── DoublyLinkedList.js ├── Queue.js ├── SinglyLinkedList.js └── Stack.js └── README.md /Chapter1/1.1-StringUniqueChars.js: -------------------------------------------------------------------------------- 1 | function hasUniqueChars(str) { 2 | //can't have unique characters if string length is greater than the # of possible characters 3 | if (str.length > 256) return false; 4 | for (var i = 0; i< str.length; i++) { 5 | if (str.indexOf(str[i]) !== str.lastIndexOf(str[i]) || str.lastIndexOf(str[i]) !== i) { 6 | return false; 7 | } 8 | } 9 | return true; 10 | } -------------------------------------------------------------------------------- /Chapter1/1.2-StringAnagrams.js: -------------------------------------------------------------------------------- 1 | function areAnagrams(str1,str2) { 2 | if (str1.length !== str2.length) return false; 3 | var str1Chars = str1.split('').sort(); //get sorted characters of the strings 4 | var str2Chars = str2.split('').sort(); 5 | var isAnagram = true; 6 | str1Chars.forEach(function (curChar, index) { 7 | if (str2Chars[index] !== curChar) { //every array position should be equal if the strings are anagrams 8 | isAnagram = false; 9 | return; 10 | } 11 | }); 12 | return isAnagram; 13 | } 14 | -------------------------------------------------------------------------------- /Chapter1/1.3-StringWhiteSpace.js: -------------------------------------------------------------------------------- 1 | /* 2 | Problem: Write a method to replace all spaces in a string with '%20'. 3 | */ 4 | /* 5 | This could be done fairly simply by using the String.replace() function. 6 | I elected to not do that for the sake of making this problem a little less trivial 7 | */ 8 | 9 | function replaceWhiteSpace(str) { 10 | var outputArr = [ ]; 11 | for (var i=0; i< str.length; i++) { 12 | if (str[i] === ' ') { 13 | outputArr.push('%'); //alternatively, you could push '%20' as one string 14 | outputArr.push('2'); 15 | outputArr.push('0'); 16 | } 17 | else outputArr.push(str[i]); 18 | } 19 | return outputArr.join(''); 20 | } 21 | -------------------------------------------------------------------------------- /Chapter1/1.4-StringCompression.js: -------------------------------------------------------------------------------- 1 | /* 2 | Problem: Implement a method to perform basic string compression using the counts of 3 | repeated characters. For example, the string aabcccccaaa would become 4 | a2blc5a3. If the "compressed" string would not become smaller than the original 5 | string, your method should return the original string. 6 | */ 7 | 8 | function stringCompression(str) { 9 | var compressedString = ''; 10 | for (var i = 0; i < str.length; i++) { 11 | var curLetter = str[i]; 12 | var curCount = 1; 13 | while (str[i+1] === curLetter) { 14 | curCount++; 15 | i++; 16 | } 17 | compressedString += curLetter + curCount; 18 | } 19 | if (compressedString.length > str.length) return str; 20 | return compressedString; 21 | } 22 | -------------------------------------------------------------------------------- /Chapter1/1.8-StringRotation.js: -------------------------------------------------------------------------------- 1 | /* 2 | Problem: Assume you have a method isSubstring which checks if one word is a substring 3 | of another. Given two strings, si and s2, write code to check Ifs2 is a rotation of si 4 | using only onecalltoisSubstring (e.g., "waterbottLe" is a rotation of "erbottLewat"). 5 | */ 6 | 7 | function isRotation(str1, str2) { //determines whether str2 is a rotation of str1 8 | if (str1.length !== str2.length || !str1.length) 9 | return false; //strings must be of equal length and str1 should not be empty 10 | var str1Twice = str1 + str1; 11 | return isSubstring(str1twice, str2); 12 | } 13 | 14 | -------------------------------------------------------------------------------- /Chapter2-LinkedLists/2.1-RemoveDups.js: -------------------------------------------------------------------------------- 1 | /* 2 | Write code to remove duplicates from an unsorted linked list. 3 | */ 4 | 5 | function removeDuplicates(firstElement) { //assumes input is the head of the LinkedList (and that it is a singly linked list) 6 | var values = [firstElement.data]; //first element is not a duplicate 7 | var prev = firstElement; 8 | var curr = firstElement.next; 9 | while (curr) { 10 | if (values.indexOf(curr.data) !== -1) { 11 | prev.next = curr.next; 12 | } else { 13 | values.push(curr.data); 14 | prev = curr; 15 | } 16 | curr = curr.next; 17 | } 18 | return; 19 | } 20 | 21 | /* 22 | Example: 23 | 1 -> 5 -> 2 -> 1 -> 2 -> 3 24 | values = [1] prev = 1 curr = 5 25 | values = [1,5] prev = 5 curr = 2 26 | values = [1,5,2] prev = 2 curr = 1 27 | values = [1,5,2] prev.next=2 (1 -> 5 -> 2 -> 1 -> 2 -> 3 becomes 1 -> 5 -> 2 -> 2 -> 3) prev = 2 (1st 2) curr = 2 (2nd 2) 28 | values = [1,5,2] prev.next = 3 prev= 2 (does not change) curr = 3 29 | values = [1,5,2,3] prev =3 curr = null 30 | */ 31 | 32 | 33 | -------------------------------------------------------------------------------- /Chapter2-LinkedLists/2.2-KthLastElement.js: -------------------------------------------------------------------------------- 1 | /* 2 | Problem: Implement an algorithm to find the kth to last element of a singly linked list. 3 | */ 4 | 5 | //input is the head of the LinkedList (as a node) and an integer k (the kth element from the end will be returned; k=1 returns the last element) 6 | function kthLastElement(head, k) { 7 | if (!head || k<= 0) return; //empty linked list or invalid input for k 8 | var curr = head; 9 | var kthNode = head; 10 | for (var i=1; i<=k; i++) { 11 | if (!kthNode) return null; //in case there are fewer than k nodes 12 | kthNode = kthNode.next; 13 | } 14 | while (kthNode) { 15 | curr = curr.next; 16 | kthNode = kthNode.next; 17 | } 18 | 19 | return curr; 20 | 21 | } 22 | 23 | 24 | 25 | /* 26 | 1 -> 5 -> 6 -> 8 -> 9 -> 2 -> 4 k=3 (should return node w/ 9) 27 | curr = 1, kth = 8 28 | 5 9 29 | 6 2 30 | 8 4 31 | 9 null 32 | */ -------------------------------------------------------------------------------- /Chapter2-LinkedLists/2.3-DeleteFromLinkedList.js: -------------------------------------------------------------------------------- 1 | /* 2 | Problem: Implement an algorithm to delete a node in the middle of a singly linked list, given only access to that node. 3 | */ 4 | 5 | function removeNode(nodeToDelete) { //this will return the value of the node you are 'deleting' 6 | if (!nodeToDelete) return; 7 | if (!nodeToDelete.next) //deleting tail of linked list 8 | throw ("this algorithm does not work for deleting the last node!"); 9 | var deletingNodeData = nodeToDelete.data; 10 | nodeToDelete.data = nodeToDelete.next.data; //copy the data of the next node 11 | nodeToDelete.next = nodeTodelete.next.next; 12 | return deletingNodeData; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /Chapter2-LinkedLists/2.4-PartitionLL.js: -------------------------------------------------------------------------------- 1 | /* 2 | Problem: Write code to partition a linked list around a value x, such that all nodes less than x 3 | come before all nodes greater than or equal to x. 4 | */ 5 | 6 | /* 7 | @params{firstElement} - first element in the list 8 | @params{x} value to partition around 9 | */ 10 | 11 | function partitionLinkedList(firstElement, x) { 12 | var prev = firstElement; 13 | var curr = firstElement.next; 14 | 15 | //if val is less than the partition, set it as the head to move it left 16 | while ( prev.next ) { 17 | if ( curr.data < x ) { 18 | prev.next = curr.next; 19 | //make a copy so we can keep incrementing from the old spot 20 | var newHead = new Node(curr.data, firstElement); 21 | firstElement = newHead; 22 | } 23 | prev = curr; 24 | curr = curr.next; 25 | } 26 | return firstElement; 27 | } 28 | 29 | //example: 3->10->11->2, paritioned around 5 becomes 2->3->10->11 -------------------------------------------------------------------------------- /Chapter3-StacksandQueues/3.2-StackMinimum.js: -------------------------------------------------------------------------------- 1 | /* 2 | Problem: How would you design a stack which, in addition to push and pop, also has a function min which returns the minimum element? Push, pop and min should all operate in O(1) time. 3 | */ 4 | 5 | MinStack.prototype = new Stack(); //inheritance 6 | MinStack.prototype.constructor = MinStack; 7 | 8 | function MinStack() { 9 | this.minStack = new Stack(); 10 | } 11 | 12 | MinStack.prototype.push = function(val) { 13 | var newNode = new Node(val); 14 | if (!this.top) { 15 | this.top = newNode; 16 | this.minStack.push(val); 17 | return; 18 | } 19 | newNode.next = this.top; 20 | this.top = newNode; 21 | if (this.minStack.peek() > val) 22 | this.minStack.push(val); 23 | }; 24 | 25 | MinStack.prototype.pop = function() { 26 | if (!this.top) return null; 27 | var popped = this.top.val; 28 | if (this.minStack.peek() === popped) 29 | this.minStack.pop(); 30 | this.top = this.top.next; 31 | return popped; 32 | }; 33 | 34 | MinStack.prototype.min = function() { 35 | return this.minStack.peek(); 36 | }; 37 | 38 | function Stack() { 39 | this.top = null; 40 | } 41 | 42 | Stack.prototype.push = function(val) { 43 | var newNode = new Node(val); 44 | if (!this.top) { 45 | this.top = newNode; 46 | return; 47 | } 48 | newNode.next = this.top; 49 | this.top = newNode; 50 | }; 51 | 52 | Stack.prototype.pop = function() { 53 | if (!this.top) return null; 54 | var popped = this.top.val; 55 | this.top = this.top.next; 56 | return popped; 57 | }; 58 | 59 | Stack.prototype.peek = function() { 60 | if (!this.top) return null; 61 | return this.top.val; 62 | }; 63 | 64 | function Node(val,next) { 65 | this.val = val; 66 | this.next = next; 67 | } 68 | -------------------------------------------------------------------------------- /Chapter3-StacksandQueues/3.3-SetOfStacks.js: -------------------------------------------------------------------------------- 1 | /* 2 | Problem: Imagine a (literal) stack of plates. If the stack gets too high, it might topple. Therefore, in real life, we would likely start a new stack when the previous stack exceeds some threshold. Implement a data structure SetOfStacks that mimics this. SetOfStacks should be composed of several stacks and should create a new stack once the previous one exceeds capacity. 3 | 4 | SetOfStacks.push() and SetOfStacks.pop () should behave identically to a single stack (that is, pop () should return the same values as it would if there were just a single stack). 5 | */ 6 | 7 | function Node(value) { 8 | this.value = value; 9 | } 10 | 11 | function Stack() { 12 | this.top = null; 13 | this.length = 0; 14 | } 15 | 16 | Stack.prototype.push = function(value) { 17 | var newNode = new Node(value); 18 | if (!this.top) { 19 | this.top = newNode; 20 | } else { 21 | newNode.next = this.top; 22 | this.top =newNode; 23 | } 24 | this.length ++; 25 | }; 26 | 27 | Stack.prototype.pop = function() { 28 | if (!this.top) return null; 29 | var popped = this.top.value; 30 | this.top = this.top.next; 31 | this.length--; 32 | return popped; 33 | }; 34 | 35 | Stack.prototype.peek = function() { 36 | if (!this.top) return null; 37 | return this.top.value; 38 | }; 39 | 40 | function setOfStacks(maxValue) { 41 | this.maxValue = maxValue || 10; //set a default max value of 10 if no max value is provided 42 | this.stackOfStacks = new Stack(); 43 | this.currentStack = null; 44 | } 45 | 46 | setOfStacks.prototype.push = function(value) { 47 | var newNode = new Node(value); 48 | if (!this.currentStack || this.currentStack.length === this.maxValue) { //need to create a new stack 49 | var newStack = new Stack(); 50 | newStack.push(new Node(value)); 51 | this.stackOfStacks.push(newStack); 52 | this.currentStack = this.stackOfStacks.peek(); 53 | } else { 54 | this.currentStack.push(newNode); 55 | } 56 | }; 57 | 58 | setOfStacks.prototype.pop = function() { 59 | if (!this.currentStack) return null; 60 | var popped = this.currentStack.pop(); 61 | if (!this.currentStack.length) { //current stack is now empty so remove it 62 | this.stackOfStacks.pop(); 63 | this.currentStack = this.stackOfStacks.peek(); 64 | } 65 | return popped; 66 | }; 67 | 68 | setOfStacks.prototype.peek = function() { 69 | if (!this.currentStack) return null; 70 | return this.currentStack.peek(); 71 | }; -------------------------------------------------------------------------------- /Chapter3-StacksandQueues/3.5-QueueTwoStacks.js: -------------------------------------------------------------------------------- 1 | /* 2 | Problem: Implement a MyQueue class which imprements a queue using two stacks 3 | */ 4 | 5 | var myQueue = function(stack1, stack2) { 6 | this.newestStack = new Stack(stack1); 7 | this.oldestStack = new Stack(stack2); 8 | }; 9 | 10 | //pushing adds value to newer stack 11 | myQueue.prototype.push = function(val) { 12 | this.newestStack.push(val); 13 | }; 14 | 15 | //shift values to oldest stack if it is empty for peek() and pop() operations 16 | myQueue.prototype.shift = function(){ 17 | if (this.oldestStack.size() === 0) { 18 | while (this.newestStack.size() > 0) { 19 | var curr = this.newestStack.pop(); 20 | this.oldestStack.push(curr); 21 | } 22 | } 23 | }; 24 | 25 | //peek from oldest stack where oldest values are on top 26 | myQueue.prototype.peek = function() { 27 | myQueue.shift(); 28 | return this.oldestStack.peek(); 29 | }; 30 | 31 | //pop from older stack 32 | myQueue.prototype.pop = function(){ 33 | myQueue.shift(); 34 | return this.oldestStack.pop(); 35 | }; 36 | 37 | //size is the two stacks combined 38 | myQueue.prototype.size = function(){ 39 | return this.newestStack.size() + this.oldestStack.size(); 40 | }; 41 | 42 | myQueue.prototype.isEmpty = function() { 43 | return (this.newestStack.size() === 0) && (this.oldestStack.size() === 0); 44 | }; -------------------------------------------------------------------------------- /Chapter3-StacksandQueues/3.6-SortedStack.js: -------------------------------------------------------------------------------- 1 | /* 2 | Problem: Write a program to sort a stack in ascending order (with biggest items on top). 3 | You may use at most one additional stack to hold items, but you may not copy the elements into any other data structure (such as an array). 4 | The stack supports the following operations: push, pop, peek, and isEmpty 5 | */ 6 | 7 | //this is the actual solution of the problem 8 | Stack.prototype.sort = function() { 9 | var currStack = this; 10 | console.log(currStack); 11 | var helperStack = new Stack(); 12 | while (!currStack.isEmpty()) { //move all elements from the stack into the helper stack, reordering the helper stack each time 13 | if (!helperStack.top) { 14 | helperStack.push(currStack.pop()); //insert initial element from top of stack into helper stack 15 | continue; 16 | } 17 | helperStack.push(currStack.pop()); 18 | var node = helperStack.top; 19 | while (node.next && node.data < node.next.data) { //swap until element is in correct position 20 | var curVal = node.data; 21 | node.data = node.next.data; 22 | node.next.data = curVal; 23 | node = node.next; 24 | } 25 | } 26 | this.top = helperStack.top; //this will effectively make the current stack the helper stack 27 | return helperStack; 28 | }; 29 | 30 | //the following is just an implementation of a Stack with the allowed methods so that I could test my solution 31 | function Node(data) { 32 | this.data = data; 33 | this.next = null; 34 | } 35 | 36 | function Stack() { 37 | this.top = null; 38 | } 39 | 40 | Stack.prototype.push = function(value) { 41 | var newNode = new Node(value); 42 | if (!this.top) { //inserting into empty queue 43 | this.top = newNode; 44 | } else { 45 | newNode.next = this.top; 46 | this.top = newNode; 47 | } 48 | }; 49 | 50 | Stack.prototype.pop = function() { 51 | if (!this.top) { 52 | return null; //empty queue 53 | } 54 | var popped = this.top.data; 55 | this.top = this.top.next; //this will either be the next node of the top element or null (if the Stack only had 1 element) 56 | return popped; 57 | }; 58 | 59 | Stack.prototype.peek = function() { 60 | if (!this.top) return null; 61 | return this.top.data; 62 | }; 63 | 64 | Stack.prototype.isEmpty = function() { 65 | if (!this.top) return true; 66 | return false; 67 | }; -------------------------------------------------------------------------------- /Chapter8-Recursion/8.1-Fibonacci.js: -------------------------------------------------------------------------------- 1 | /* 2 | Problem: Write a method to generate the nth Fibonacci number. 3 | */ 4 | 5 | function getFib(n) { 6 | if (n < 0) 7 | throw new TypeError("Input must be positive!"); 8 | if (n === 0) { 9 | return 0; 10 | } 11 | if (n === 1) { 12 | return 1; 13 | } 14 | return getFib(n-1) + getFib(n-2); 15 | } -------------------------------------------------------------------------------- /Chapter8-Recursion/8.2-GridPaths.js: -------------------------------------------------------------------------------- 1 | /* 2 | Problem: Imagine a robot sitting on the upper left hand corner of an NxN grid. The robot can 3 | only move in two directions: right and down. How many possible paths are there for 4 | the robot? 5 | */ 6 | 7 | 8 | //n represents the size of the length and width of an NxN grid 9 | //memoizing so memory overflow does not happen 10 | var numPaths = { }; 11 | function getPaths(n, xPos, yPos) { 12 | var xPos = xPos || 0; 13 | var yPos = yPos || 0; 14 | if (xPos === n) //if at max xPos, you have only 1 option- go down 15 | return 1; 16 | if (yPos === n) //if at max yPos, you have to go right 17 | return 1; 18 | //otherwise, you can either go right or go down 19 | return memoize(n, xPos + 1, yPos) + memoize(n, xPos, yPos + 1); 20 | } 21 | 22 | function memoize(n, xPos, yPos) { 23 | if (numPaths[[n,xPos,yPos]]) 24 | return numPaths[[n,xPos,yPos]]; 25 | numPaths[[n,xPos,yPos]] = getPaths(n,xPos,yPos); 26 | return numPaths[[n,xPos,yPos]]; 27 | } -------------------------------------------------------------------------------- /Chapter8-Recursion/8.4-StringPermutations.js: -------------------------------------------------------------------------------- 1 | /* 2 | Problem: Write a method to compute all permutations of a string 3 | */ 4 | 5 | function getStringPermutations(str) { 6 | var permutations = [ ]; 7 | var letters = str.split(''); 8 | getPermutations(letters); 9 | function getPermutations(letters) { 10 | permutations.push([letters.shift()]); 11 | while (letters.length) { 12 | var curRes = [ ]; 13 | var curLetter = letters.shift(); 14 | permutations.forEach(function (letters) { 15 | for (var i = 0 ; i <= letters.length ; i++) { 16 | var tmp = letters.slice(); 17 | tmp.splice(i,0,curLetter); 18 | curRes.push(tmp); 19 | } 20 | }); 21 | permutations = curRes; //permutations needs to now be the results we have just generated 22 | } 23 | } 24 | return permutations.map(function(permutation) { 25 | return permutation.join(''); //we want the permutations to be strings not arrays 26 | }).filter(function (permutation, index, arr) { 27 | return arr.indexOf(permutation) === index; //only want unique values 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /Chapter8-Recursion/8.5-ValidParenthesesCombos.js: -------------------------------------------------------------------------------- 1 | /* 2 | Implement an algorithm to print all valid (i.e. properly opened and closed) combinations of n-pairs of parentheses 3 | */ 4 | 5 | function validParentheses(n) { 6 | var combos = [ ]; 7 | function getCombinations(openNum,closingNum,curr) { 8 | if (openNum === 0 && closingNum === 0) 9 | combos.push(curr); 10 | if (openNum > 0) { 11 | getCombinations(openNum-1, closingNum + 1, curr + "("); 12 | } 13 | if (closingNum > 0) { 14 | getCombinations(openNum, closingNum - 1, curr + ")"); 15 | } 16 | } 17 | getCombinations(n,0,""); 18 | return combos; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /DataStructures/BinarySearchTree.js: -------------------------------------------------------------------------------- 1 | var BST = function(val) { 2 | this.val = val; 3 | }; 4 | 5 | BST.prototype.contains = function(val) { 6 | var curr = this; 7 | var found = false; 8 | 9 | while(!found && curr) { 10 | if (val === curr.val) { 11 | found = true; 12 | } 13 | if (val > curr.val){ 14 | curr = curr.right; 15 | } else if (val < curr.val) { 16 | curr = curr.left; 17 | } 18 | } 19 | return found; 20 | }; 21 | 22 | BST.prototype.insert = function(val){ 23 | var valNode = new BST(val); 24 | 25 | while(true) { 26 | if (val < this.val) { 27 | if (!this.left) { 28 | this.left = valNode; 29 | break; 30 | } else { 31 | return this.left.insert(val); 32 | } 33 | } else if (val > this.val) { 34 | if (!this.right) { 35 | this.right = valNode; 36 | break; 37 | } else { 38 | return this.right.insert(val) 39 | } 40 | } else return; 41 | } 42 | }; 43 | 44 | BST.prototype.traverse = function(process){ 45 | function processNode(node) { 46 | if (node.left) { 47 | processNode(node.left) 48 | } 49 | process.call(this, node.val); 50 | if (node.right) { 51 | processNode(node.right); 52 | } 53 | } 54 | processNode(this); 55 | }; 56 | 57 | BST.prototype.size = function(){ 58 | var length = 0; 59 | 60 | this.traverse(function(node){ 61 | length ++; 62 | }); 63 | return length; 64 | }; 65 | 66 | BST.prototype.toArray = function(){ 67 | var array = []; 68 | 69 | this.traverse(function(node){ 70 | array.push(node.val); 71 | }); 72 | return array; 73 | }; 74 | 75 | BST.prototype.remove = function(value) { 76 | var curr = this; 77 | var parent = null; 78 | var found = false; 79 | var direction = null; 80 | while (!found) { 81 | if ( value === curr.val) { 82 | found = true; 83 | } 84 | if (value < curr.val) { 85 | parent = curr; 86 | direction = 'left'; 87 | curr = curr.left; 88 | } else if (value > curr.val) { 89 | parent = curr; 90 | direction = 'right'; 91 | curr = curr.right; 92 | } 93 | } 94 | //no children - just remove node 95 | if (!curr.left && !curr.right) { 96 | parent[direction] = null; 97 | //two children 98 | } else if (curr.left && curr.right) { 99 | var opposite = direction === 'right' ? 'left' : 'right'; 100 | var last = curr[opposite]; 101 | while (last[opposite]) { 102 | last = last[opposite]; 103 | } 104 | curr.val = last.val; 105 | 106 | if (direction === 'left') { 107 | last = curr.right; 108 | while (last.right) { 109 | last = last.right; 110 | } 111 | curr.val = last.val; 112 | } 113 | //one child - replace node with child 114 | } else { 115 | if (direction === 'left') { 116 | if (curr.left) parent.left = curr.left; 117 | else parent.left = curr.right; 118 | } else { 119 | if (curr.left) parent.right = curr.left; 120 | else parent.right = curr.right; 121 | } 122 | } 123 | } -------------------------------------------------------------------------------- /DataStructures/DoublyLinkedList.js: -------------------------------------------------------------------------------- 1 | /* 2 | A Javascript implementation of a Doubly Linked List (this implementation keeps track of both the head and tail) 3 | Methods include inserting and deleting from both the head and tail 4 | */ 5 | 6 | function Node(data, previous, next) { 7 | this.data = data; 8 | this.previous = previous; 9 | this.next = next; 10 | } 11 | 12 | function LinkedList() { 13 | this.head = null; 14 | this.tail = null; 15 | } 16 | 17 | LinkedList.prototype.insertAtHead = function (data) { 18 | if (!this.head) { //empty list so the new node becomes both the head and the tail 19 | var newNode = new Node(data,null,null); 20 | this.head = newNode; 21 | this.tail = newNode; 22 | } else { 23 | var currHead = this.head; 24 | var newHead = new Node(data, null, currHead); 25 | currHead.previous = newHead; 26 | this.head = newHead; 27 | } 28 | }; 29 | 30 | LinkedList.prototype.insertAtTail = function (data) { //a 'push' function 31 | if (!this.tail) { //empty list 32 | var newNode = new Node(data,null,null); 33 | this.head = newNode; 34 | this.tail = newNode; 35 | } else { 36 | var currTail = this.tail; 37 | var newTail = new Node(data,currTail, null); 38 | currTail.next = newTail; 39 | this.tail = newTail; 40 | } 41 | }; 42 | 43 | LinkedList.prototype.removeHead = function () { //removes the head of the LinkedList and returns its value 44 | if (!this.head) 45 | return; //empty LinkedList 46 | var value = this.head.data; 47 | this.head = this.head.next; 48 | if (this.head) { 49 | this.head.previous = null; //if the removed element was not the only node in the LinkedList 50 | } else { 51 | this.tail = null; //the only element was removed so we now have an empty LinkedList 52 | } 53 | return value; 54 | }; 55 | 56 | LinkedList.prototype.removeTail = function () { //remove the tail of the LinkedList and return its value 57 | if (!this.tail) 58 | return; //empty LinkedList 59 | var value = this.tail.data; 60 | this.tail = this.tail.previous; 61 | if (this.tail) { //check if the LinkedList is non empty 62 | this.tail.next = null; 63 | } else { 64 | this.head = null; //LinkedList is empty now 65 | } 66 | return value; 67 | }; 68 | 69 | LinkedList.prototype.search = function (value) { // returns first node with value or null if value not in LinkedList 70 | if (!this.head) return null; //empty LinkedList 71 | var curr = this.head; 72 | while (curr.data !== value) { 73 | if (!curr.next) 74 | return null; //at end of LinkedList (element not found) 75 | curr = curr.next; 76 | } 77 | return curr; 78 | }; -------------------------------------------------------------------------------- /DataStructures/Queue.js: -------------------------------------------------------------------------------- 1 | function Node(data) { 2 | this.data = data; 3 | this.next = null; 4 | } 5 | 6 | function Queue() { 7 | this.first = null; 8 | this.last = null; 9 | } 10 | 11 | Queue.prototype.enqueue = function(value) { 12 | var newNode = new Node(value); 13 | if (!this.first) { 14 | //adding to an empty queue 15 | this.first = newNode; 16 | this.last = newNode; 17 | return; 18 | } 19 | this.last.next = newNode; 20 | this.last = newNode; 21 | }; 22 | 23 | Queue.prototype.dequeue = function() { 24 | if (!this.first) 25 | return null; 26 | var popped = this.first.data; 27 | this.first = this.first.next; 28 | if (!this.first) //removing the only node in the queue 29 | this.last = null; 30 | return popped; 31 | }; 32 | 33 | Queue.prototype.peek = function() { 34 | if (!this.first) return null; 35 | return this.first.data; 36 | }; -------------------------------------------------------------------------------- /DataStructures/SinglyLinkedList.js: -------------------------------------------------------------------------------- 1 | /* 2 | A Javascript implementation of a Singly Linked List with methods for insertion (at the end of the Linked List), search, and deletion 3 | */ 4 | 5 | function Node(data, next) { 6 | this.data = data; 7 | this.next = next; 8 | } 9 | 10 | function LinkedList() { 11 | this.head = null; 12 | } 13 | 14 | LinkedList.prototype.insert = function (data) { //inserts node with value of data at end of linked list 15 | if (!this.head) { 16 | var newHead = new Node(data,null); 17 | this.head = newHead; 18 | } else { 19 | var curr = this.head; 20 | while (curr.next) { 21 | curr = curr.next; //iterate until you have the last element (the tail of the LinkedList) 22 | } 23 | var newNode = new Node(data,null); 24 | curr.next = newNode; 25 | } 26 | }; 27 | 28 | //this delete function will remove the first node with the value (can be modified to remove multiple/all nodes w/ value instead if desired) 29 | LinkedList.prototype.delete = function (valToDelete) { 30 | if (!this.head) return; //empty LinkedList 31 | if (this.head.data === valToDelete) { //remove the head 32 | this.head = this.head.next; 33 | return; 34 | } 35 | var curr = this.head; 36 | while (curr.next.data !== valToDelete) { 37 | if (curr.next === null) 38 | return; //on the last node so stop iterating (value not found) 39 | curr = curr.next; 40 | } 41 | curr.next = curr.next.next; 42 | return; 43 | }; 44 | 45 | LinkedList.prototype.search = function (value) { // returns first node with value or null if value not in LinkedList 46 | if (!this.head) return null; //empty LinkedList 47 | var curr = this.head; 48 | while (curr.data !== value) { 49 | if (!curr.next) 50 | return null; //at end of LinkedList (element not found) 51 | curr = curr.next; 52 | } 53 | return curr; 54 | }; -------------------------------------------------------------------------------- /DataStructures/Stack.js: -------------------------------------------------------------------------------- 1 | function Node(data) { 2 | this.data = data; 3 | this.next = null; 4 | } 5 | 6 | function Stack() { 7 | this.top = null; 8 | } 9 | 10 | Stack.prototype.push = function(value) { 11 | var newNode = new Node(value); 12 | if (!this.top) { //inserting into empty queue 13 | this.top = newNode; 14 | } else { 15 | newNode.next = this.top; 16 | this.top = newNode; 17 | } 18 | }; 19 | 20 | Stack.prototype.pop = function() { 21 | if (!this.top) { 22 | return null; //empty queue 23 | } 24 | var popped = this.top.data; 25 | this.top = this.top.next; //this will either be the next node of the top element or null (if the Stack only had 1 element) 26 | return popped; 27 | }; 28 | 29 | Stack.prototype.peek = function() { 30 | if (!this.top) return null; 31 | return this.top.data; 32 | }; 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ##### Disclaimer ~9 years later 2 | I started this repository in 2015. Since then JS has changed quite a lot. I haven't made any changes to incorporate things like Javascript classes, `let` and `const`, new methods and functions, or any of the many other new features introduced in the last 9+ years. I probably will not though who knows. If you found this somehow and found it helpful, I'm glad it provided some value and welcome any feedback or suggestions. 3 | 4 | ##### These are my solutions to problems from the book *Cracking the Coding Interview* (5th edition) in Javascript. I am also adding my implementations of common data structures. ##### 5 | 6 | The problems in the book are created for Java and C++ so not all are well suited for Javascript. Whenever possible, I have tried to do problems in the way the authors intended them to be done (for example, not using arrays to implement things like linked lists, stacks, and queues). 7 | 8 | I welcome any and all feedback– there are any issues, please feel free to add a Github issue. Additionally, I encourage contributions to this project. If you have your own solution in Javascript, please make a pull request. 9 | --------------------------------------------------------------------------------