diff --git a/chapter01/1.1 - Is Unique/isUnique.js b/chapter01/1.1 - Is Unique/isUnique.js index 136496c..3321571 100644 --- a/chapter01/1.1 - Is Unique/isUnique.js +++ b/chapter01/1.1 - Is Unique/isUnique.js @@ -12,5 +12,31 @@ var allUniqueChars = function(string) { return true; // if no match, return true }; +const everyCharUnique = (str, indexOffset = 'a'.charCodeAt()) => { + let counterTable = Number(); + for(let index of [...str].map(c => c.charCodeAt() - indexOffset)) { + const mask = 1 << index; + if(counterTable & mask) + return false; + counterTable |= mask; + } + return true; +}; + +function everyCharUnique(str) { + let obj = {}; + for (let i = 0; i < str.length; i++) { + if (obj[str[i]] && obj[str[i]] >= 1) { + return false; + } else { + obj[str[i]] = 1; + } + } + return true; +} + /* TESTS */ -// log some tests here \ No newline at end of file +console.log(everyCharUnique('abcd'), 'true'); +console.log(everyCharUnique('abccd'), 'false'); +console.log(everyCharUnique('bhjjb'), 'false'); +console.log(everyCharUnique('mdjq'), 'true'); diff --git a/chapter01/1.3 - URLify/urlify-2.js b/chapter01/1.3 - URLify/urlify-2.js new file mode 100644 index 0000000..be53567 --- /dev/null +++ b/chapter01/1.3 - URLify/urlify-2.js @@ -0,0 +1,11 @@ +const replaceUrlSpaces = (str) => { + const convertToArray = str.trim().split(''); + for(let i in convertToArray) { + if(convertToArray[i] === " ") { + convertToArray[i] = "%20" + } + } + return convertToArray.join(''); +} + + console.log(replaceUrlSpaces("Sai Charan P")); diff --git a/chapter01/1.3 - URLify/urlify-3.js b/chapter01/1.3 - URLify/urlify-3.js new file mode 100644 index 0000000..3add8f9 --- /dev/null +++ b/chapter01/1.3 - URLify/urlify-3.js @@ -0,0 +1,20 @@ +function urlify(str, len) { + let s = ""; + let totalSpaces = str.length - len; + let frontSpaces = 0; + let flag = false; + for (let i = 0; i < str.length; i++) { + if (flag === false) { + if (str[i] === " ") frontSpaces++; + else flag = true; + } + if (flag === true && i < str.length - (totalSpaces - frontSpaces)) { + if (str[i] === " ") s += "%20"; + else s += str[i]; + } + } + + return s; +} + +console.log(urlify("Mr John Smith ", 13)); diff --git a/chapter01/1.4 - PalinPerm/palinPerm2.js b/chapter01/1.4 - PalinPerm/palinPerm2.js new file mode 100644 index 0000000..bf0f525 --- /dev/null +++ b/chapter01/1.4 - PalinPerm/palinPerm2.js @@ -0,0 +1,20 @@ +function palinPerm(s) { + const sanitized = s.toUpperCase().split(" ").join(""); + const freq = new Map(); + for (let i = 0; i < sanitized.length; i++) { + const char = sanitized.charAt(i); + const prevFreq = freq.get(char) || 0; + freq.set(char, prevFreq + 1); + } + let oddCount = 0; + for (let char of freq) { + if (char[1] % 2 !== 0) { + oddCount++; + } + } + return oddCount < 2; +} + +// TESTS +console.log(palinPerm('Tact Coa'), 'true'); +console.log(palinPerm('Tact boa'), 'false'); diff --git a/chapter02/2.1 - Remove Dups/removeDups.js b/chapter02/2.1 - Remove Dups/removeDups.js index 1a34d5b..c424136 100644 --- a/chapter02/2.1 - Remove Dups/removeDups.js +++ b/chapter02/2.1 - Remove Dups/removeDups.js @@ -1,82 +1,38 @@ -/* CLASS */ -var LinkedList = function(value) { - this.value = value; - this.next = null; -}; - -/* FUNCTIONS */ -var checkDups = function(head, node) { - var currNode = head; - while (currNode !== node) { - if (currNode.value === node.value) { - return true; +// remiveDups redone +const LinkedList = require("../util/LinkedListX"); + +function removeDuplicates(list) { + const _set = new Set(); + let cur = list.head; + let prev = null; + while (cur) { + if (_set.has(cur.value)) { + // duplicate found + // de-link it from the list + // cur jumps next but previous stays + // right behind cur (as always) + let elem = cur; + prev.next = cur.next; + cur = cur.next; + elem.next = null; } - currNode = currNode.next; - } - return false; -}; - -var printLinkedList = function(head) { - var node = head; - console.log('start of linked list'); - while (node !== null) { - console.log(node.value); - node = node.next; - } - console.log('end of linked list'); -}; - -var removeDups = function(head) { - var node = head; - while (node !== null) { - if (node.next !== null && checkDups(head, node.next)) { - node.next = node.next.next; - } else { - node = node.next; + else { + // add to the set + _set.add(cur.value); + prev = cur; + cur = cur.next; } } - return head; -}; - -/* TESTS */ -var a = new LinkedList('a'); -var b = new LinkedList('b'); -var c = new LinkedList('c'); -var d = new LinkedList('d'); -var e = new LinkedList('e'); - -a.next = b; -b.next = c; -c.next = d; -d.next = e; - -removeDups(a); -printLinkedList(a); - -var f = new LinkedList('f'); -var g = new LinkedList('g'); -var h = new LinkedList('g'); -var i = new LinkedList('g'); -var j = new LinkedList('g'); - -f.next = g; -g.next = h; -h.next = i; -i.next = j; -removeDups(f); -printLinkedList(f); + return list; +} -var k = new LinkedList('g'); -var l = new LinkedList('g'); -var m = new LinkedList('g'); -var n = new LinkedList('b'); -var o = new LinkedList('g'); +// quick test +let list = new LinkedList(); +for (let elem of [1, 5, 1, 6, 8, 6, 8, 8, 8, 8]) { + list.append(elem); +} -k.next = l; -l.next = m; -m.next = n; -n.next = o; +removeDuplicates(list); -removeDups(k); -printLinkedList(k); +console.log(list._toArray()); // [1, 5, 6, 8] diff --git a/chapter02/2.2 - Return Kth to Last/returnKthToLast.js b/chapter02/2.2 - Return Kth to Last/returnKthToLast.js index 7d3b742..5c740e1 100644 --- a/chapter02/2.2 - Return Kth to Last/returnKthToLast.js +++ b/chapter02/2.2 - Return Kth to Last/returnKthToLast.js @@ -1,42 +1,41 @@ -var linkedList = function(value) { - this.value = value; - this.next = null; -}; +const LinkedList = require("../util/LinkedListX"); + +var findKthToLast = function(k, list) { + // do iteratively + //define two pointers , fast and slow pointer + let fast = list.head + let slow = list.head + + //Move fast pointer k steps in the linkedlist while slow remains at head + for(let i=0;i b -> c -> d -> e -> f, input c -// a -> b -> *d -> d -> e -> f -// a -> b -> d -> *e -> e -> f -// a -> b -> d -> e -> *f -> f -// a -> b -> d -> e -> f -> *null - /* TEST */ -var printList = function(head) { - while(head !== null) { - console.log(head.value); - head = head.next; - } - console.log('done printing'); -}; - -var a = new LinkedList('a'); -var b = new LinkedList('b'); -var c = new LinkedList('c'); -var d = new LinkedList('d'); -var e = new LinkedList('e'); -var f = new LinkedList('f'); - -a.next = b; -b.next = c; -c.next = d; -d.next = e; -e.next = f; +let list = new LinkedList(); +for (let item of [1, 2, 3, 4, 5, 6]) { + list.append(item); +} -printList(a); -deleteMidNode(c); -printList(a); +printList(list.head); +deleteMidNode(list.head.next); +printList(list.head); diff --git a/chapter02/2.4 - Partition/partition.js b/chapter02/2.4 - Partition/partition.js index 841f687..6253911 100644 --- a/chapter02/2.4 - Partition/partition.js +++ b/chapter02/2.4 - Partition/partition.js @@ -8,8 +8,10 @@ var partition = function(head, partition) { // and attach nodes with values less than partition value to the left // and nodes with vallues more than partition value to the right var left; + var middle; var right; var currLeft = null; + var currMiddle = null; var currRight = null; var node = head; @@ -22,6 +24,14 @@ var partition = function(head, partition) { currLeft.next = node; currLeft = currLeft.next; } + } else if (node.value === partition) { + if (currMiddle === null) { + middle = node; + currMiddle = middle; + } else { + currMiddle.next = node; + currMiddle = currMiddle.next; + } } else { if (currRight === null) { right = node; @@ -34,13 +44,16 @@ var partition = function(head, partition) { node = node.next; } currRight.next = null; - currLeft.next = right; // connect two partitions together + // connect the left values with those matching the partition value + currLeft.next = middle; + // connect the middle with the right partitions + currMiddle.next = right; return left; // return head of new linkedList }; /* TESTS */ // Input: 3 -> 5 -> 8 -> 5 -> 10 -> 2 -> 1 [partition = 5] -// Output: 3 -> 1 -> 2 -> 10 -> 5 -> 5 -> 8 +// Output: 3 -> 2 -> 1 -> 5 -> 5 -> 8 -> 10 var printList = function(a) { while (a !== null) { diff --git a/chapter02/2.8 - Loop Detection/loopDetection.js b/chapter02/2.8 - Loop Detection/loopDetection.js index c444194..4026c02 100644 --- a/chapter02/2.8 - Loop Detection/loopDetection.js +++ b/chapter02/2.8 - Loop Detection/loopDetection.js @@ -1,22 +1,27 @@ var LinkedList = require('./../util/LinkedList'); var loopDetection = (head) => { - var hare = head; - var tortoise = head; - while (hare !== null) { - tortoise = tortoise.next; - hare = hare.next; - if (hare === tortoise && hare !== head.next) { - return true; - } - if (hare !== null) { - hare = hare.next; - if (hare === tortoise) { - return true; - } - } + // The null checking code will handle lists with no loops. + if (!head || !head.next) return null + + var hare = head + var tortoise = head + + do { + hare = hare.next + tortoise = tortoise.next + if (!hare || !hare.next) return null + hare = hare.next + } while (hare !== tortoise) + + tortoise = head + + while (hare !== tortoise) { + hare = hare.next + tortoise = tortoise.next } - return false; + + return hare }; /* TEST */ @@ -36,7 +41,7 @@ d.next = e; e.next = f; f.next = c; -console.log(loopDetection(a), true); +console.log(loopDetection(a) === c, true); var A = new LinkedList(); var B = new LinkedList(); @@ -51,4 +56,4 @@ C.next = D; D.next = E; E.next = F; -console.log(loopDetection(A), false); +console.log(loopDetection(A) === null, false); diff --git a/chapter02/util/LinkedListX.js b/chapter02/util/LinkedListX.js new file mode 100644 index 0000000..1e19a5b --- /dev/null +++ b/chapter02/util/LinkedListX.js @@ -0,0 +1,157 @@ +// a new implementation of the linked list +/* +ADT: +# Main operations +prepend(value) -> Add a node in the beginning +append(value) -> Add a node in the end +pop() -> Remove a node from the end +popFirst() -> Remove a node from the beginning +head() -> Return the first node +tail() -> Return the last node +remove(Node)* -> Remove Node from the list +*/ + +// NOTE: no type-safety + +class Node { + constructor(value) { + this.value = value + this.next = null; + } + } + + class LinkedList { + constructor() { + this.head = null; + this.tail = null; + } + + append(value) { + let node = new Node(value); + // if list is empty + if (!this.head) { + this.head = node; + this.tail = node; + } + else { + this.tail.next = node; + this.tail = node; + } + } + + prepend(value) { + let node = new Node(value); + node.next = this.head; + this.head = node; + } + + pop() { + let cur = this.head; + + // only one or no item exists + if (!cur) return null; + if (!cur.next) { + this.head = null; + return cur; + } + // move till the 2nd last + while (cur.next.next) + cur = cur.next; + + let last = this.tail; + this.tail = cur; + this.tail.next = null; + return last; + } + + popFirst() { + let first = this.head; + if (this.head && this.head.next) { + this.head = this.head.next; + first.next = null; + } + else this.head = null; + return first; + } + + head() { + return this.head; + } + + removeAt(index) { + let i = 0; + let cur = this.head; + let prev = null; + + while (cur != null) { + if (i == index) { + // remove + if (prev == null) + this.head = cur.next; + else prev.next = cur.next; + cur.next = null; + return cur.value; + } + else { + prev = cur; + cur = cur.next; + i++; + } + } + return null; + } + + insertAt(index, value) { + if (index == 0) return this.prepend(value); + let cur = this.head; + let i = 0; + + while (cur != null) { + if (i == index - 1) { + let node = new Node(value); + node.next = cur.next; + cur.next = node; + return true; + } + else { + i++; + cur = cur.next; + } + } + return false; + } + + tail() { + return this.tail; + } + + _toArray() { + let arr = []; + let cur = this.head; + while (cur) { + arr.push(cur.value); + cur = cur.next; + } + + return arr; + } + } + + module.exports = LinkedList; + + /* TEST */ + + // let l = new LinkedList(); + // l.append(3); + // l.append(4); + // l.append(10); + // l.append(20); + // l.append(5); + + // console.log(l.removeAt(1), 4); + // console.log(l.pop().value, 5); + + // console.log(l._toArray()); + // l.insertAt(2, 40); + // console.log(l._toArray()); + \ No newline at end of file diff --git a/chapter03/3.1 - Three in One/threeInOne.js b/chapter03/3.1 - Three in One/threeInOne.js index 147b6c7..f7917c4 100644 --- a/chapter03/3.1 - Three in One/threeInOne.js +++ b/chapter03/3.1 - Three in One/threeInOne.js @@ -44,12 +44,12 @@ ThreeInOne.prototype.pop2 = function() { return answer; }; -ThreeInOne.prototype.pop3 = function(value) { +ThreeInOne.prototype.pop3 = function() { if (this.isEmpty3()) { return undefined; } - return this.container.pop(value); + return this.container.pop(); }; ThreeInOne.prototype.peek1 = function() { diff --git a/chapter03/3.2 - Stack Min/stackMin.js b/chapter03/3.2 - Stack Min/stackMin.js index a818e39..4d5c4ff 100644 --- a/chapter03/3.2 - Stack Min/stackMin.js +++ b/chapter03/3.2 - Stack Min/stackMin.js @@ -1,43 +1,40 @@ var Stack = require('./../util/Stack'); // Approach, keep an additional stack that keeps the mins -var stackMin = function() { - this.stack = new Stack(); - this.minStack = new Stack(); - this.currMin = undefined; -}; - -stackMin.prototype.push = function(value) { - if (this.currMin === undefined || value <= this.currMin) { - this.minStack.push(this.currMin); - this.currMin = value; - } - this.stack.push(value); -}; -stackMin.prototype.pop = function() { - var answer = this.stack.pop(); - if (answer === this.currMin) { - this.currMin = this.minStack.pop(); +class StackMin extends Stack { + constructor() { + super(); + // additional stack to track the mins + this._minStack = new Stack(); + this._min = null; } - return answer; -}; -stackMin.prototype.peek = function() { - return this.stack.peek(); -}; + push(value) { + super.push(value); + if (this._min == null || value <= this._min) { + this._min = value; + this._minStack.push(value); + } + } -stackMin.prototype.isEmpty = function() { - return this.stack.isEmpty(); -}; + pop() { + let value = super.pop(); + if (value == this._minStack.peek()) { + this._minStack.pop(); + this._min = this._minStack.peek(); + } + return value; + } -stackMin.prototype.min = function() { - return this.currMin; -}; + min() { + return this._min; + } +} /* TEST */ -var s = new stackMin(); +var s = new StackMin(); s.push(9); s.push(8); s.push(1); @@ -57,4 +54,4 @@ console.log(s.min(), 8); s.pop(); s.pop(); console.log(s.isEmpty(), true); -console.log(s.min(), undefined); +console.log(s.min(), null); diff --git a/chapter03/3.3 - Stack of Plates/stackOfPlates.js b/chapter03/3.3 - Stack of Plates/stackOfPlates.js index 3fe3bdf..7232bfb 100644 --- a/chapter03/3.3 - Stack of Plates/stackOfPlates.js +++ b/chapter03/3.3 - Stack of Plates/stackOfPlates.js @@ -1,40 +1,59 @@ -var SetOfStacks = function(capacity) { - // implement as an array of stacks - this.capacity = capacity; - this.stackSet = []; -}; +// implement as array of stacks +const Stack = require("../util/Stack"); -SetOfStacks.prototype.push = function(value) { - if (this.stackSet.length === 0 || this.stackSet[this.stackSet.length - 1].length === this.capacity) { - var newStack = []; - newStack.push(value); - this.stackSet.push(newStack); - } else { - this.stackSet[this.stackSet.length - 1].push(value); +class SetOfStacks { + constructor(capacity) { + this.capacity = capacity; + this.stackSet = []; } -}; -SetOfStacks.prototype.pop = function() { - if (this.numStack === 0) { - return undefined; - } else if (this.stackSet[this.stackSet.length - 1].length === 0) { - this.stackSet.pop(); - } - return this.stackSet[this.stackSet.length - 1].pop(); -}; + getLastStack() { + return this.stackSet[this.stackSet.length - 1]; + } + + push(value) { + let last = this.getLastStack(); + if (this.stackSet.length === 0 || last.size() === this.capacity) { + var newStack = new Stack(); + newStack.push(value); + this.stackSet.push(newStack); + } else { + last.push(value); + } + } -SetOfStacks.prototype.peek = function() { - var currStack = this.stackSet[this.stackSet.length - 1]; - return currStack[currStack.length - 1]; -}; + pop() { + if (this.stackSet.length === 0) { + return undefined; + } + let last = this.getLastStack(); + let value = last.pop(); + if (last.size() === 0) { + this.stackSet.pop(); + } + return value; + } + + peek() { + let last = this.getLastStack(); + return last.peek(); + } -SetOfStacks.prototype.isEmpty = function() { - return this.stackSet.length === 0; -}; + isEmpty() { + return this.stackSet.length === 0; + } -SetOfStacks.prototype.popAt = function(index) { - return this.stackSet[index].pop(); -}; + popAt(index) { + // out of range index + if (index < 0 || index >= this.stackSet.length) return false; + let value = this.stackSet[index].pop(); + if (this.stackSet[index].size() == 0) { + // clear the stack from the set + this.stackSet.splice(index, 1); + } + return value; + } +} /* TESTS */ @@ -54,11 +73,13 @@ s.push(12); s.push(13); s.push(14); -console.log(s.stackSet); +console.log(s.peek(), 14); +s.popAt(2); +s.popAt(2); s.popAt(2); -console.log(s.stackSet); +console.log(s.peek(), 14); s.pop(); s.pop(); @@ -70,8 +91,4 @@ s.pop(); s.pop(); s.pop(); -console.log(s.stackSet); - - -// Note: if stack not implemented as an array, would need to separately keep track of the depth -// of each stack in an array +console.log(s.peek(), 2); diff --git a/chapter03/3.4 - Queue via Stacks/queueViaStacks.js b/chapter03/3.4 - Queue via Stacks/queueViaStacks.js index bb9f48e..c205431 100644 --- a/chapter03/3.4 - Queue via Stacks/queueViaStacks.js +++ b/chapter03/3.4 - Queue via Stacks/queueViaStacks.js @@ -1,47 +1,49 @@ var Stack = require('./../util/Stack'); -var myQueue = function() { - this.front = new Stack(); - this.back = new Stack(); - this.backUp = true; -}; +class MyQueue { + constructor() { + this.front = new Stack(); + this.back = new Stack(); + this.backUp = true; + } -myQueue.prototype.add = function(value) { - if (!this.backUp) { - while (!this.front.isEmpty()) { - this.back.push(this.front.pop()); + add(value) { + if (!this.backUp) { + while (!this.front.isEmpty()) { + this.back.push(this.front.pop()); + } + this.backUp = true; } - this.backUp = true; + this.back.push(value); } - this.back.push(value); -}; -myQueue.prototype.remove = function() { - if (this.backUp) { - while(!this.back.isEmpty()) { - this.front.push(this.back.pop()); + remove() { + if (this.backUp) { + while(!this.back.isEmpty()) { + this.front.push(this.back.pop()); + } + this.backUp = false; } - this.backUp = false; + return this.front.pop(); } - return this.front.pop(); -}; -myQueue.prototype.peek = function() { - if (this.backUp) { - while(!this.back.isEmpty()) { - this.front.push(this.back.pop()); + peek() { + if (this.backUp) { + while(!this.back.isEmpty()) { + this.front.push(this.back.pop()); + } + this.backUp = false; } - this.backUp = false; + return this.front.peek(); } - return this.front.peek(); -}; -myQueue.prototype.isEmpty = function() { - return this.front.isEmpty() && this.back.isEmpty(); -}; + isEmpty() { + return this.front.isEmpty() && this.back.isEmpty(); + } +} /* TEST */ -var m = new myQueue(); +var m = new MyQueue(); console.log(m.isEmpty(), true); m.add('a'); diff --git a/chapter03/3.6 - Animal Shelter/animalShelter.js b/chapter03/3.6 - Animal Shelter/animalShelter.js index 342f14d..73471d1 100644 --- a/chapter03/3.6 - Animal Shelter/animalShelter.js +++ b/chapter03/3.6 - Animal Shelter/animalShelter.js @@ -12,7 +12,7 @@ var AnimalShelter = function() { AnimalShelter.prototype.enqueue = function(animal) { if (animal.type === 'dog') { this.dogQ.enqueue(animal); - } else if (animal.type === 'vat') { + } else if (animal.type === 'cat') { this.catQ.enqueue(animal); } this.allQ.enqueue(animal); diff --git a/chapter03/util/LinkedList.js b/chapter03/util/LinkedList.js index 6164dbc..2037ae9 100644 --- a/chapter03/util/LinkedList.js +++ b/chapter03/util/LinkedList.js @@ -1,6 +1,143 @@ -var LinkedList = function(value) { - this.value = value; - this.next = null; -}; +// moved from chapter 2 (/util/LinkedListX.js) -module.exports = LinkedList; \ No newline at end of file +class Node { + constructor(value) { + this.value = value + this.next = null; + } +} + +class LinkedList { + constructor() { + this.head = null; + this.tail = null; + } + + append(value) { + let node = new Node(value); + // if list is empty + if (!this.head) { + this.head = node; + this.tail = node; + } + else { + this.tail.next = node; + this.tail = node; + } + } + + prepend(value) { + let node = new Node(value); + node.next = this.head; + this.head = node; + } + + pop() { + let cur = this.head; + + // only one or no item exists + if (!cur) return null; + if (!cur.next) { + this.head = null; + return cur; + } + // move till the 2nd last + while (cur.next.next) + cur = cur.next; + + let last = this.tail; + this.tail = cur; + this.tail.next = null; + return last; + } + + popFirst() { + let first = this.head; + if (this.head && this.head.next) { + this.head = this.head.next; + first.next = null; + } + else this.head = null; + return first; + } + + head() { + return this.head; + } + + removeAt(index) { + let i = 0; + let cur = this.head; + let prev = null; + + while (cur != null) { + if (i == index) { + // remove + if (prev == null) + this.head = cur.next; + else prev.next = cur.next; + cur.next = null; + return cur.value; + } + else { + prev = cur; + cur = cur.next; + i++; + } + } + return null; + } + + insertAt(index, value) { + if (index == 0) return this.prepend(value); + let cur = this.head; + let i = 0; + + while (cur != null) { + if (i == index - 1) { + let node = new Node(value); + node.next = cur.next; + cur.next = node; + return true; + } + else { + i++; + cur = cur.next; + } + } + return false; + } + + tail() { + return this.tail; + } + + _toArray() { + let arr = []; + let cur = this.head; + while (cur) { + arr.push(cur.value); + cur = cur.next; + } + + return arr; + } +} + +module.exports = LinkedList; + +/* TEST */ + +// let l = new LinkedList(); +// l.append(3); +// l.append(4); +// l.append(10); +// l.append(20); +// l.append(5); + +// console.log(l.removeAt(1), 4); +// console.log(l.pop().value, 5); + +// console.log(l._toArray()); +// l.insertAt(2, 40); +// console.log(l._toArray()); diff --git a/chapter03/util/Queue.js b/chapter03/util/Queue.js index 55b8c4d..1eeab01 100644 --- a/chapter03/util/Queue.js +++ b/chapter03/util/Queue.js @@ -1,41 +1,36 @@ // implement a queue using linkedLists var LinkedList = require('./LinkedList'); -var Queue = function() { - this.front = null; - this.back = null; -}; - -Queue.prototype.add = function(value) { - var node = new LinkedList(value); - if (this.front === null) { - this.front = node; - this.back = node; - } else { - var prevBack = this.back; - this.back = node; - prevBack.next = this.back; +class Queue { + constructor() { + this._list = new LinkedList(); } -}; - -Queue.prototype.remove = function() { - var removed = this.front; - if (this.front === this.back) { - this.front = null; - this.back = null; - } else { - this.front = this.front.next; + + enqueue(value) { + this._list.append(value); + } + + dequeue() { + let node = this._list.popFirst(); + return node.value; + } + + peek() { + return this._list.head ? this._list.head.value : null; + } + + isEmpty() { + return this._list.head == null; } - return removed !== null ? removed.value : null; -}; -Queue.prototype.peek = function() { - return this.front !== null ? this.front.value : null; -}; + _toArray() { + return this._list._toArray(); + } +} -Queue.prototype.isEmpty = function() { - return this.front === null; -}; +// alias +Queue.prototype.add = Queue.prototype.enqueue; +Queue.prototype.remove = Queue.prototype.dequeue; module.exports = Queue; @@ -44,8 +39,10 @@ module.exports = Queue; // q.add('a'); // q.add('b'); // q.add('c'); +// console.log(q._toArray()); // console.log(q.remove(), 'a'); // console.log(q.peek(), 'b'); // console.log(q.remove(), 'b'); // console.log(q.remove(), 'c'); // console.log(q.isEmpty(), true); +// console.log(q._toArray()); diff --git a/chapter03/util/Stack.js b/chapter03/util/Stack.js index 99cc0ea..a84844f 100644 --- a/chapter03/util/Stack.js +++ b/chapter03/util/Stack.js @@ -1,31 +1,44 @@ -// implement a stack using linkedLists -var LinkedList = require('./LinkedList'); - -var Stack = function() { - this.top = null; -}; - -Stack.prototype.push = function(value) { - var node = new LinkedList(value); - node.next = this.top; - this.top = node; -}; - -Stack.prototype.pop = function() { - var popped = this.top; - if (this.top !== null) { - this.top = this.top.next; +// simple implementation of a stack +// using an Array + +/* +Interface: +- push(value) +- pop() +- peek() +- isEmpty() +- size() +*/ +class Stack { + constructor() { + this._data = []; } - return popped.value; -}; -Stack.prototype.peek = function() { - return this.top !== null ? this.top.value : null; -}; + size() { + return this._data.length; + } + + isEmpty() { + return this.size() == 0; + } + + push(value) { + this._data.push(value); + } -Stack.prototype.isEmpty = function() { - return this.top === null; -}; + pop() { + return this._data.pop(); + } + + peek() { + if (this.isEmpty()) return null; + return this._data[this.size() - 1]; + } + + _toArray() { + return this._data; + } +} module.exports = Stack; @@ -39,4 +52,4 @@ module.exports = Stack; // console.log(s.peek(), 'b'); // console.log(s.pop(), 'b'); // console.log(s.pop(), 'a'); -// console.log(s.isEmpty(), true); \ No newline at end of file +// console.log(s.isEmpty(), true); diff --git a/chapter04/util/LinkedList.js b/chapter04/util/LinkedList.js index 6164dbc..67713c9 100644 --- a/chapter04/util/LinkedList.js +++ b/chapter04/util/LinkedList.js @@ -1,6 +1,144 @@ -var LinkedList = function(value) { - this.value = value; - this.next = null; -}; +// moved from chapter 2 (/util/LinkedListX.js) -module.exports = LinkedList; \ No newline at end of file +class Node { + constructor(value) { + this.value = value + this.next = null; + } + } + + class LinkedList { + constructor() { + this.head = null; + this.tail = null; + } + + append(value) { + let node = new Node(value); + // if list is empty + if (!this.head) { + this.head = node; + this.tail = node; + } + else { + this.tail.next = node; + this.tail = node; + } + } + + prepend(value) { + let node = new Node(value); + node.next = this.head; + this.head = node; + } + + pop() { + let cur = this.head; + + // only one or no item exists + if (!cur) return null; + if (!cur.next) { + this.head = null; + return cur; + } + // move till the 2nd last + while (cur.next.next) + cur = cur.next; + + let last = this.tail; + this.tail = cur; + this.tail.next = null; + return last; + } + + popFirst() { + let first = this.head; + if (this.head && this.head.next) { + this.head = this.head.next; + first.next = null; + } + else this.head = null; + return first; + } + + head() { + return this.head; + } + + removeAt(index) { + let i = 0; + let cur = this.head; + let prev = null; + + while (cur != null) { + if (i == index) { + // remove + if (prev == null) + this.head = cur.next; + else prev.next = cur.next; + cur.next = null; + return cur.value; + } + else { + prev = cur; + cur = cur.next; + i++; + } + } + return null; + } + + insertAt(index, value) { + if (index == 0) return this.prepend(value); + let cur = this.head; + let i = 0; + + while (cur != null) { + if (i == index - 1) { + let node = new Node(value); + node.next = cur.next; + cur.next = node; + return true; + } + else { + i++; + cur = cur.next; + } + } + return false; + } + + tail() { + return this.tail; + } + + _toArray() { + let arr = []; + let cur = this.head; + while (cur) { + arr.push(cur.value); + cur = cur.next; + } + + return arr; + } + } + + module.exports = LinkedList; + + /* TEST */ + + // let l = new LinkedList(); + // l.append(3); + // l.append(4); + // l.append(10); + // l.append(20); + // l.append(5); + + // console.log(l.removeAt(1), 4); + // console.log(l.pop().value, 5); + + // console.log(l._toArray()); + // l.insertAt(2, 40); + // console.log(l._toArray()); + \ No newline at end of file diff --git a/chapter04/util/Queue.js b/chapter04/util/Queue.js index 55b8c4d..1eeab01 100644 --- a/chapter04/util/Queue.js +++ b/chapter04/util/Queue.js @@ -1,41 +1,36 @@ // implement a queue using linkedLists var LinkedList = require('./LinkedList'); -var Queue = function() { - this.front = null; - this.back = null; -}; - -Queue.prototype.add = function(value) { - var node = new LinkedList(value); - if (this.front === null) { - this.front = node; - this.back = node; - } else { - var prevBack = this.back; - this.back = node; - prevBack.next = this.back; +class Queue { + constructor() { + this._list = new LinkedList(); } -}; - -Queue.prototype.remove = function() { - var removed = this.front; - if (this.front === this.back) { - this.front = null; - this.back = null; - } else { - this.front = this.front.next; + + enqueue(value) { + this._list.append(value); + } + + dequeue() { + let node = this._list.popFirst(); + return node.value; + } + + peek() { + return this._list.head ? this._list.head.value : null; + } + + isEmpty() { + return this._list.head == null; } - return removed !== null ? removed.value : null; -}; -Queue.prototype.peek = function() { - return this.front !== null ? this.front.value : null; -}; + _toArray() { + return this._list._toArray(); + } +} -Queue.prototype.isEmpty = function() { - return this.front === null; -}; +// alias +Queue.prototype.add = Queue.prototype.enqueue; +Queue.prototype.remove = Queue.prototype.dequeue; module.exports = Queue; @@ -44,8 +39,10 @@ module.exports = Queue; // q.add('a'); // q.add('b'); // q.add('c'); +// console.log(q._toArray()); // console.log(q.remove(), 'a'); // console.log(q.peek(), 'b'); // console.log(q.remove(), 'b'); // console.log(q.remove(), 'c'); // console.log(q.isEmpty(), true); +// console.log(q._toArray()); diff --git a/chapter04/util/Stack.js b/chapter04/util/Stack.js index 99cc0ea..a04e649 100644 --- a/chapter04/util/Stack.js +++ b/chapter04/util/Stack.js @@ -1,31 +1,40 @@ -// implement a stack using linkedLists -var LinkedList = require('./LinkedList'); - -var Stack = function() { - this.top = null; -}; - -Stack.prototype.push = function(value) { - var node = new LinkedList(value); - node.next = this.top; - this.top = node; -}; - -Stack.prototype.pop = function() { - var popped = this.top; - if (this.top !== null) { - this.top = this.top.next; +// simple implementation of a stack +// using an Array + +/* +Interface: +- push(value) +- pop() +- peek() +- isEmpty() +- size() +*/ +class Stack { + constructor() { + this._data = []; } - return popped.value; -}; -Stack.prototype.peek = function() { - return this.top !== null ? this.top.value : null; -}; + size() { + return this._data.length; + } + + isEmpty() { + return this.size() == 0; + } + + push(value) { + this._data.push(value); + } + + pop() { + return this._data.pop(); + } -Stack.prototype.isEmpty = function() { - return this.top === null; -}; + peek() { + if (this.isEmpty()) return null; + return this._data[this.size() - 1]; + } +} module.exports = Stack; @@ -39,4 +48,4 @@ module.exports = Stack; // console.log(s.peek(), 'b'); // console.log(s.pop(), 'b'); // console.log(s.pop(), 'a'); -// console.log(s.isEmpty(), true); \ No newline at end of file +// console.log(s.isEmpty(), true); diff --git a/chapter05/5.1 - Insertion/insertion.js b/chapter05/5.1 - Insertion/insertion.js index f7c05fa..350df6b 100644 --- a/chapter05/5.1 - Insertion/insertion.js +++ b/chapter05/5.1 - Insertion/insertion.js @@ -1,14 +1,11 @@ -var insertion = function(N, M, i, j) { - var n = N.split(''); - var m = M.split(''); - var nlength = n.length - 1; - var mlength = m.length - 1; - for (var a = 0; a < j - i + 1; a++) { - console.log(m[mlength - a]); - n[nlength - (i + a)] = m[mlength - a]; - } - return n.join(''); +const insertion = (N, M, i, j) => { + const bitMask = (-1 << (j + 1)) | ((1 << i) - 1); + const clearedN = N & bitMask; + const shiftedM = M << i; + return clearedN | shiftedM; }; /* TEST */ -console.log(insertion('10000000000', '10011', 2, 6), '10001001100'); \ No newline at end of file +const N = parseInt(10000000000, 2); +const M = parseInt(10011, 2); +console.log(insertion(M, N, 2, 6).toString(2), 10001001100); diff --git a/chapter07/util/LinkedList.js b/chapter07/util/LinkedList.js index 6164dbc..67713c9 100644 --- a/chapter07/util/LinkedList.js +++ b/chapter07/util/LinkedList.js @@ -1,6 +1,144 @@ -var LinkedList = function(value) { - this.value = value; - this.next = null; -}; +// moved from chapter 2 (/util/LinkedListX.js) -module.exports = LinkedList; \ No newline at end of file +class Node { + constructor(value) { + this.value = value + this.next = null; + } + } + + class LinkedList { + constructor() { + this.head = null; + this.tail = null; + } + + append(value) { + let node = new Node(value); + // if list is empty + if (!this.head) { + this.head = node; + this.tail = node; + } + else { + this.tail.next = node; + this.tail = node; + } + } + + prepend(value) { + let node = new Node(value); + node.next = this.head; + this.head = node; + } + + pop() { + let cur = this.head; + + // only one or no item exists + if (!cur) return null; + if (!cur.next) { + this.head = null; + return cur; + } + // move till the 2nd last + while (cur.next.next) + cur = cur.next; + + let last = this.tail; + this.tail = cur; + this.tail.next = null; + return last; + } + + popFirst() { + let first = this.head; + if (this.head && this.head.next) { + this.head = this.head.next; + first.next = null; + } + else this.head = null; + return first; + } + + head() { + return this.head; + } + + removeAt(index) { + let i = 0; + let cur = this.head; + let prev = null; + + while (cur != null) { + if (i == index) { + // remove + if (prev == null) + this.head = cur.next; + else prev.next = cur.next; + cur.next = null; + return cur.value; + } + else { + prev = cur; + cur = cur.next; + i++; + } + } + return null; + } + + insertAt(index, value) { + if (index == 0) return this.prepend(value); + let cur = this.head; + let i = 0; + + while (cur != null) { + if (i == index - 1) { + let node = new Node(value); + node.next = cur.next; + cur.next = node; + return true; + } + else { + i++; + cur = cur.next; + } + } + return false; + } + + tail() { + return this.tail; + } + + _toArray() { + let arr = []; + let cur = this.head; + while (cur) { + arr.push(cur.value); + cur = cur.next; + } + + return arr; + } + } + + module.exports = LinkedList; + + /* TEST */ + + // let l = new LinkedList(); + // l.append(3); + // l.append(4); + // l.append(10); + // l.append(20); + // l.append(5); + + // console.log(l.removeAt(1), 4); + // console.log(l.pop().value, 5); + + // console.log(l._toArray()); + // l.insertAt(2, 40); + // console.log(l._toArray()); + \ No newline at end of file diff --git a/chapter07/util/Queue.js b/chapter07/util/Queue.js index 55b8c4d..1eeab01 100644 --- a/chapter07/util/Queue.js +++ b/chapter07/util/Queue.js @@ -1,41 +1,36 @@ // implement a queue using linkedLists var LinkedList = require('./LinkedList'); -var Queue = function() { - this.front = null; - this.back = null; -}; - -Queue.prototype.add = function(value) { - var node = new LinkedList(value); - if (this.front === null) { - this.front = node; - this.back = node; - } else { - var prevBack = this.back; - this.back = node; - prevBack.next = this.back; +class Queue { + constructor() { + this._list = new LinkedList(); } -}; - -Queue.prototype.remove = function() { - var removed = this.front; - if (this.front === this.back) { - this.front = null; - this.back = null; - } else { - this.front = this.front.next; + + enqueue(value) { + this._list.append(value); + } + + dequeue() { + let node = this._list.popFirst(); + return node.value; + } + + peek() { + return this._list.head ? this._list.head.value : null; + } + + isEmpty() { + return this._list.head == null; } - return removed !== null ? removed.value : null; -}; -Queue.prototype.peek = function() { - return this.front !== null ? this.front.value : null; -}; + _toArray() { + return this._list._toArray(); + } +} -Queue.prototype.isEmpty = function() { - return this.front === null; -}; +// alias +Queue.prototype.add = Queue.prototype.enqueue; +Queue.prototype.remove = Queue.prototype.dequeue; module.exports = Queue; @@ -44,8 +39,10 @@ module.exports = Queue; // q.add('a'); // q.add('b'); // q.add('c'); +// console.log(q._toArray()); // console.log(q.remove(), 'a'); // console.log(q.peek(), 'b'); // console.log(q.remove(), 'b'); // console.log(q.remove(), 'c'); // console.log(q.isEmpty(), true); +// console.log(q._toArray()); diff --git a/chapter07/util/Stack.js b/chapter07/util/Stack.js index 99cc0ea..a04e649 100644 --- a/chapter07/util/Stack.js +++ b/chapter07/util/Stack.js @@ -1,31 +1,40 @@ -// implement a stack using linkedLists -var LinkedList = require('./LinkedList'); - -var Stack = function() { - this.top = null; -}; - -Stack.prototype.push = function(value) { - var node = new LinkedList(value); - node.next = this.top; - this.top = node; -}; - -Stack.prototype.pop = function() { - var popped = this.top; - if (this.top !== null) { - this.top = this.top.next; +// simple implementation of a stack +// using an Array + +/* +Interface: +- push(value) +- pop() +- peek() +- isEmpty() +- size() +*/ +class Stack { + constructor() { + this._data = []; } - return popped.value; -}; -Stack.prototype.peek = function() { - return this.top !== null ? this.top.value : null; -}; + size() { + return this._data.length; + } + + isEmpty() { + return this.size() == 0; + } + + push(value) { + this._data.push(value); + } + + pop() { + return this._data.pop(); + } -Stack.prototype.isEmpty = function() { - return this.top === null; -}; + peek() { + if (this.isEmpty()) return null; + return this._data[this.size() - 1]; + } +} module.exports = Stack; @@ -39,4 +48,4 @@ module.exports = Stack; // console.log(s.peek(), 'b'); // console.log(s.pop(), 'b'); // console.log(s.pop(), 'a'); -// console.log(s.isEmpty(), true); \ No newline at end of file +// console.log(s.isEmpty(), true); diff --git a/chapter08/8.01 - Triple Step/tripleStepv2.js b/chapter08/8.01 - Triple Step/tripleStepv2.js new file mode 100644 index 0000000..32ae4d8 --- /dev/null +++ b/chapter08/8.01 - Triple Step/tripleStepv2.js @@ -0,0 +1,62 @@ +/* +Recursion and Dynamic Programming (4 steps) +1. start with the recursive backtracking solution (brute force) +2. Optimize by using a memoization table (top-down dynamic programming) +3. Remove the need for recursion (bottom-up dynamic programming) +4. Apply final tricks to reduce the time / memory complexity +*/ + +// Recursive Backtracking +// Time & Space O(n!) +function tripleStep(n) { + if (n < 0) return 0; + if (n === 0) return 1; + return tripleStep(n - 1) + tripleStep(n - 2) + tripleStep(n - 3); +} + +// Top Down Memoization +// Time & Space O(n) +function tripleStep(n, i = 3, memo = [1, 1, 2, 4]) { + if (n < 0) return 0 + if (n < i) return memo[n]; + memo[i] = memo[i - 1] + memo[i - 2] + memo[i - 3]; + return tripleStep(n, i + 1, memo); +} + +// Bottom Up memoization +// Time & Space O(n) +function tripleStep(n, memo = [1, 1, 2, 4]) { + for (let i = 3; i <= n; i++) { + memo[i] = memo[i - 1] + memo[i - 2] + memo[i - 3]; + } + + return memo[memo.length - 1]; +} + +// Constant Space +// Time O(n) & Space O(1) +function tripleStep(n) { + if (n <= 0) return 0; + if (n === 1) return 1; + if (n === 2) return 2; + + let a = 1; + let b = 1; + let c = 2; + + for (let i = 3; i < n; i++) { + let d = a + b + c; + a = b; + b = c; + c = d; + } + return a + b + c; +} + +/* TEST */ +console.log(tripleStep(1), 1); +console.log(tripleStep(2), 2); +console.log(tripleStep(3), 4); +console.log(tripleStep(5), 13); +console.log(tripleStep(7), 44); +console.log(tripleStep(10), 274); diff --git a/chapter10/10.08 - Find Duplicates/findDuplicates.js b/chapter10/10.08 - Find Duplicates/findDuplicates.js index 07bfb1c..1562e64 100644 --- a/chapter10/10.08 - Find Duplicates/findDuplicates.js +++ b/chapter10/10.08 - Find Duplicates/findDuplicates.js @@ -1,2 +1,49 @@ -// sort numbers -// stream through numbers and print elements which is a duplicate of the immediate previous number +// We're given 4 kilobytes (4 * 2^10 * 8 = 32*2^10 bits) of main memory(RAM) to write a program to print all duplicate entries in an array +// from 1 to N where N is at most 32,000 (32*2^10). + +// We can use an Int8Array that uses 1 Byte per element to store 0's if we haven't seen it and 1's if we have seen it. +// The Int8Array typed array represents an array of twos-complement 8-bit signed integers. +// 4 KB > 32,000 bits + +// Time Complexity - O(n) +// Space Complexity - O(n) + +// Let's have a JavaScript Solution of this program: + +function FindDuplicates(arr, range = 32000) { + // Initialize integer 8 bit array with 0's at every index + const numbersSeen = new Int8Array(range); + const duplicates = []; + for (let i = 0; i < arr.length; i++) { + if (numbersSeen[arr[i]] === 0) { + numbersSeen[arr[i]] = 1; + } else { + duplicates.push(arr[i]); + } + } + return duplicates; +} + + const arr = [ + 0, + 1, + 1, + 2, + 4, + 6, + 7, + 9, + 9, + 34, + 56, + 78, + 90, + 101, + 345, + 789, + 999, + 999, + 11000 + ]; + FindDuplicates(arr); +// [1, 9, 999] diff --git a/package.json b/package.json index 975ebe9..aaa9743 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ }, "dependencies": {}, "devDependencies": { - "eslint": "^3.14.1" + "eslint": "^6.6.0" }, "license": "MIT" }