Creating a Minstack using ES6 - javascript

I am attempting to produce the solution for the great MinStack problem and I am trying to write it using ES6 notation. I have been able to accomplish the problem using ES5 class notation and I cannot figure out what is wrong with my code. For some reason in my push method in my MinStack, the value I pass in becomes undefined. Thus when I print out min._min.storage all of the values are undefined. Any help is greatly appreciated and happy coding!
class Stack {
constructor(capacity) {
this.capacity = capacity;
this.count = 0;
this.storage = {};
}
push(value) {
console.log('here is this and your value', this, value) //value is undefined when _.min.push(value) is called
if (this.count === this.capacity) {
return 'Max capacity already reached. Remove element before adding a new one.';
} else {
this.storage[this.count++] = value;
}
}
// Time complexity: 0(1);
pop() {
var poppedElement = this.storage[--this.count];
delete this.storage[this.count];
if (this.count < 0) {
this.count = 0;
}
return poppedElement;
};
// Time complexity: 0(1)
peek() {
return this.storage[this.count - 1];
};
// Time complexity: 0(1)
count() {
return this.count;
};
}
// Time complexity: 0(1)
//1.
class MinStack extends Stack {
constructor(capacity) {
super(capacity);
this._min = new Stack(capacity);
}
push(value) {
if (this.count < this.capacity) {
if (value < this._min.peek()) {
this._min.push(value);
} else {
this._min.push(this._min.peek());
}
this.storage[this.count++] = value;
return this.count;
}
}
pop() {
const poppedElement = this.storage[--this.count];
this._min.pop();
delete this.storage[this.count];
if (this.count < 0) {
this.count = 0;
}
return poppedElement;
}
min() {
return this._min.peek();
}
peek() {
return this.storage[this.count - 1];
}
count() {
return this.count;
}
}
var min = new MinStack(6);
min.push(1);
min.push(2)
min.push(1)
min.push(0)
min.push(3)
min.push(5)
console.log(min);
console.log(min.min()) //undefined

Related

Counting values of a stack using a javascript algorithm

I need help figuring out how to make a JavaScript algorithm that count the values of a stack, I am given 3 custom methods
stack - a Stack object containing zero or more values.
.pop() which pops the top value of the stack
.push() which pushes a value on to the stack
.peek() which shows me the top value of the stack without modifying the stack
I tried simply returning the length of said stack like so
function countValues(stack) {
return stack.length
}
but i get back undefined thus having no success
this is the stack class that was used to implement the custom methods
class Stack {
constructor(...values) {
const data = {};
let index = 0;
this.push = function (value) {
if (arguments.length < 1) {
throw new TypeError('stack.push() requires a value argument');
}
if (typeof value === 'undefined') {
throw new TypeError('stack.push(value) received undefined');
}
data[index] = value;
index++;
};
this.pop = function () {
const last = index - 1;
if (last < 0) return;
const value = data[last];
delete data[last];
index = last;
return value;
};
this.peek = function () {
const last = index - 1;
if (last < 0) return;
return data[last];
};
this.print = function () {
if (index === 0) {
return 'Stack { <empty> }';
}
let output = ' }';
let last = index - 1;
for (; last > 0; last--) {
output = ' <- ' + JSON.stringify(data[last]) + output;
}
output = JSON.stringify(data[last]) + output;
return 'Stack { ' + output;
};
for (let i = 0; i < values.length; i++) {
this.push(values[i]);
}
Object.freeze(this);
}
}
class Stack {
constructor(...values) {
const data = {};
let index = 0;
this.push = function(value) {
if (arguments.length < 1) {
throw new TypeError('stack.push() requires a value argument');
}
if (typeof value === 'undefined') {
throw new TypeError('stack.push(value) received undefined');
}
data[index] = value;
index++;
};
this.pop = function() {
const last = index - 1;
if (last < 0) return;
const value = data[last];
delete data[last];
index = last;
return value;
};
this.peek = function() {
const last = index - 1;
if (last < 0) return;
return data[last];
};
this.print = function() {
if (index === 0) {
return 'Stack { <empty> }';
}
let output = ' }';
let last = index - 1;
for (; last > 0; last--) {
output = ' <- ' + JSON.stringify(data[last]) + output;
}
output = JSON.stringify(data[last]) + output;
return 'Stack { ' + output;
};
for (let i = 0; i < values.length; i++) {
this.push(values[i]);
}
Object.freeze(this);
}
}
const myStack = new Stack(1, 2, 3, 4, 5);
// Here's an easy but not so good way:
function countValues1(stack) {
return Array.from(stack.print()).filter(x => x === "<").length + 1;
}
// Here's another way, but it mutates the stack:
function countValues2(stack) {
let count = 0;
while (true) {
if (stack.pop() === undefined) {
break;
}
count++;
}
return count;
}
console.log(countValues1(myStack));
console.log(countValues2(myStack));
Without knowing exactly how stack works, or specifically what you need (are you allowed to modify the stack implementation? are you allowed to mutate the contents of the stack?) we'll struggle for a good answer, but the above should help get you maybe slightly closer perhaps.
Maybe this can help you doing a length function manually.
You should check how you declared your stack, .length is supposed to be working.
function countValues(stack) {
const tempStack = stack;
var length=0;
while(tempStack.pop()!=undefined){
length++;
}
return length;
}
This function allows you to run it and still keeping your data in the original stack.
length is a getter, which is essentially a function posing as a property. It will just return undefined if you call it on an object that doesn't implement it. If the exercise -- I assume that's what it is -- says you can only use the abovementioned methods, then you can't use object.length.

How to return an iterator in entries, keys and values methods of a linked list?

I'm trying to implement an Array-like linked list (same methods). I have the following two classes:
class Node {
constructor(value, next_node=null, prev_node=null) {
this.value = value;
this.next_node = next_node;
this.prev_node = prev_node;
}
}
class List {
constructor() {
this.head = null;
this.tail = null;
this.length = 0;
}
}
I'm trying to implement values(), entries() and keys() similar to of Array. My code:
[Symbol.iterator]() {
let current = this.head;
return {
next() {
if (current) {
let value = current.value;
current = current.next;
return {value: value, done: false};
}
return {done: true};
}
};
}
entries() {
return this._entries();
}
keys() {
return this._keys();
}
values() {
return this._values();
}
* _entries() {
var node = this.head;
var counter = 0;
while (node) {
yield [counter,node.value];
node = node.next_node;
counter += 1;
}
}
* _keys() {
var node = this.head;
var counter = 0;
while (node) {
yield counter;
node = node.next_node;
counter += 1;
}
}
* _values() {
var node = this.head;
while (node) {
yield node.value;
node = node.next_node;
}
}
Comparing between array.entries() and list.entries() I see:
Object [Array Iterator] {}
Object [Generator] {}
I understand that there is a difference between an iterator and generator. Two questions:
Should I keep it as Generator? Why Array uses Array Iterator instead of a Generator?
If I should switch to an iterator, how it should be done for those methods? As you can see, I implemented [Symbol.iterator](), but how do I use it in entries(), keys() and values()?
I understand that there is a difference
Only in syntax, basically a generator is syntax sugar for implementing Symbol.iterator. It makes it so that you don't need to worry about handling internal state like done etc, and just worry about how to yield.
If I should switch to an iterator,
If you mean move away from using generators, as there both iterators internally anyway, then I would say no, generators are much easier to code and reason with, and implementing Symbol.iterator manually would be step backwards.
Also you can keep your code a little bit more DRY here, below is an example.
class X {
[Symbol.iterator]() { return this.values(); }
*values() {
yield 1;
yield 2;
yield 3;
}
}
const x = new X();
//Both are iterators..
console.log('x.values() is iterator? ' +(Symbol.iterator in x.values()));
console.log('x is iterator? ' + (Symbol.iterator in x));
//Both work the same.
for (const a of x.values()) console.log(a);
for (const a of x) console.log(a);
If you want to use [Symbol.iterator] for entries(), you have to return a new object with *[Symbol.iterator]
class List {
constructor(min, max) {
this.min = min
this.max = max
}
entries() {
const {
min,
max
} = this
return {
*[Symbol.iterator]() {
for (let i = min; i <= max; i += 1) {
yield i
}
}
}
}
}
const list = new List(2, 7)
console.log([...list.entries()])
for (const item of list.entries()) {
console.log(item)
}

JavaScript adding "return" method to an iterator doesn't properly close the iterator

I am learning the JavaScript ES6 iterator pattern and came across this problem:
const counter = [1, 2, 3, 4, 5];
const iter = counter[Symbol.iterator]();
iter.return = function() {
console.log("exiting early");
return { done: true };
};
for (let i of iter) {
console.log(i);
if (i >= 3) {
break;
}
}
console.log('---');
for (let i of iter) {
console.log(i);
}
// 1
// 2
// 3
// exiting early
// ---
// 4
// 5
So I added a return method definition to the iterator that I extracted from an array. Although the return method got called, it didn't actually close the iterator. By contrast, if I define the iterator return method in definition, it will work as expected:
class Counter {
[Symbol.iterator]() {
let count = 1;
return {
next() {
if (count <= 5) {
return {
done: false,
value: count++
}
} else {
return {
done: true,
value: undefined
}
}
},
return() {
console.log('exiting early');
return { done: true, value: undefined };
}
}
}
}
const myCounter = new Counter();
iter = myCounter[Symbol.iterator]();
for (let i of myCounter) {
console.log(i);
if (i >= 3) {
break;
}
}
console.log('---');
for (let i of myCounter) {
console.log(i);
}
// 1
// 2
// 3
// exiting early
// ---
// 1
// 2
// 3
// 4
// 5
My question is, why did I get this unexpected behavior? I assume that if the return method didn't get called, then the iterator will not close until it reaches the very end by calling next. But adding return property will properly "call" the return method since I got the console log, but doesn't actually terminate the iterator even if I returned { done: true } in the return method.
Neither of your two return methods actually close the iterator. To achieve that, they need to record the new state of the iterator, and by that cause the next method to also return {done: true} in all subsequent calls - that's what "closed" actually means.
We can see this behaviour in action with a generator:
const iter = function*(){ yield 1; yield 2; yield 3; }();
console.log(iter.next());
console.log(iter.return());
console.log(iter.next());
Your first snippet has the problem that you've overwritten iter.return, and your method gets called (as seen from the log) but it never actually closes iter. The underlying problem is that array iterators cannot be closed, they don't normally have a return method at all. You'd have to overwrite the iter.next method as well to simulate this.
Your second snippet has the problem that it's not actually trying to iterate the iter, but it's iterating the myCounter twice which creates a new iterator object for each loop. Instead we need to use a [Symbol.iterator] method that returns the same object multiple times, easiest done by having Counter implement the iterator interface itself. We can now reproduce the unexpected behaviour:
class Counter {
count = 1;
[Symbol.iterator]() {
return this;
}
next() {
if (this.count <= 5) {
return {done: false, value: this.count++ };
} else {
return {done: true, value: undefined};
}
}
return() {
console.log('exiting early');
return { done: true, value: undefined };
}
}
const iter = new Counter();
for (let i of iter) {
console.log(i);
if (i >= 3) {
break;
}
}
console.log('---');
for (let i of iter) {
console.log(i);
}
To fix the behaviour, we would close the iterator by having the return method set the count beyond 5:
class Counter {
count = 1;
[Symbol.iterator]() {
return this;
}
next() {
if (this.count <= 5) {
return {done: false, value: this.count++ };
} else {
return {done: true, value: undefined};
}
}
return() {
this.count = 6;
// ^^^^^^^^^^^^^^^
console.log('exiting early');
return { done: true, value: undefined };
}
}
const iter = new Counter();
for (let i of iter) {
console.log(i);
if (i >= 3) {
break;
}
}
console.log('---');
for (let i of iter) {
console.log(i); // not executed!
}
Your example can be simplified as
let count = 1;
const iter = {
[Symbol.iterator]() { return this; },
next() {
if (count <= 5) {
return {
done: false,
value: count++
}
} else {
return {
done: true,
value: undefined
}
}
},
return() {
console.log('exiting early');
return { done: true, value: undefined };
}
};
for (let i of iter) {
console.log(i);
if (i >= 3) {
break;
}
}
console.log('---');
for (let i of iter) {
console.log(i);
}
so iter is just a normal object. You are passing it to a for..of loop twice.
You are making incorrect assumptions about how the interface for iterators works. The core issue is that there is nothing in this code that stores and tracks the fact that iter has returned done: true once, and thus should continue to do so. If that is the behavior you want, you need to do that yourself, e.g.
let count = 1;
let done = false;
const iter = {
[Symbol.iterator]() { return this; },
next() {
if (!done && count <= 5) {
return {
value: count++
}
} else {
done = true;
return { done };
}
},
return() {
done = true;
console.log('exiting early');
return { done };
}
};
A for..of loop essentially calls .next() until the return result is done: true, and calls .return in some cases. It is up to the implementation of the iterator itself to ensure that it properly enters a "closed" state.
All of this can also be simplified by using a generator function, since generator objects have that internal "closed" state included automatically as a side-effect of the function having returned, e.g.
function* counter() {
let counter = 1;
while (counter <= 5) yield counter++;
}
const iter = counter();
for (let i of iter) {
console.log(i);
if (i >= 3) {
break;
}
}
console.log('---');
for (let i of iter) {
console.log(i);
}

Is this a memoïze function?

Is this a memoïze function?
Secondly,
is it an efficient one?
function memoïze(func) {
var array = [];
return (value) => {
var index = array.findIndex((item) => item.lastValue == value);
if (index >= 0) {
return array[index].lastResult;
} else {
var result = func(value);
var obj = {
lastValue: value,
lastResult: result,
};
array.push(obj);
return obj.lastResult;
}
};
}
I do not like that am storing two things for each call!
Yes, it is a memoization function, but it's not an efficient one, because is uses an O(n) lookup into an array instead of using an O(1) Map lookup.
Here's a more modern efficient version:
function memoize(factory, ctx) {
const cache = new Map();
return function(key) {
if (!cache.has(key)) {
cache.set(key, factory.call(ctx, key));
}
return cache.get(key);
}
}
with sample usage:
var fib = memoize(n => n < 2 ? 1 : fib(n - 1) + fib(n - 2));
where the usage of the cache improves the performance of the algorithm from O(1.6 ^ n) to O(n) for new values, and O(1) for previously calculated values, while still preserving the recursive nature of the algorithm.
NB: for fib(50) this takes under 200µS on my laptop whereas the non-memoized version takes over three minutes.
What you have here is a closure.
Your array doesnt get garbage collected because it still has an reference to your inner function.
You have a memoization, but it can be improved.
To make it more efficient i would go with an object witch has an access time of O(1) while you have an access time of O(n):
function memorise(func) {
var cache = {};
return (value) => {
if(value in cache) return cache[value];
var result = func(value);
cache[value] = result;
return result;
}
};
Example witch object:
function memorise() {
var cache = {};
return (value) => {
if(value in cache) return cache[value];
cache[value] = value;
return value;
}
};
let mem = memorise();
console.time('chrono 1');
for(let i = 0; i < 10000; i++) {
mem(i);
}
console.timeEnd('chrono 1');
console.time('chrono 2');
for(let i = 0; i < 10000; i++) {
mem(i);
}
console.timeEnd('chrono 2');
Example with array:
function memorise() {
var array = [];
return (value) => {
var index = array.findIndex((item) => item.lastValue == value);
if (index >= 0) {
return array[index].lastResult;
} else {
var obj = {
lastValue: value,
lastResult: "someval",
};
array.push(obj);
return obj.lastResult;
}
};
}
let mem = memorise();
for(let i = 0; i < 100000; i++) {
mem(i);
}
console.time();
for(let i = 0; i < 100000; i++) {
mem(i);
}
console.timeEnd();
as it is a concept of programming which I did not know, I made some personal tests on this type of coding.
Here is the result of these tests: a universal memoïze function?
const square = n => Math.pow(n, 2)
, cube = n => Math.pow(n, 3)
, multply = (a,b) => a * b
;
function memoïze(func)
{
let cache = {}
return (...vals) => {
let ref = JSON.stringify(vals)
if(ref in cache) return cache[ref]
// console.log('no cache for', ref)
let res = func(...vals)
cache[ref] = res
return res
}
}
let m_square = memoïze( square )
let m_cube = memoïze( cube )
let m_multply = memoïze( multply )
console.log( m_square(8)) // 64
console.log( m_cube(5) ) // 125
console.log( m_multply(3,7) ) // 21
console.log( '-- result with cache: --' )
console.log( m_square(8)) // 64
console.log( m_cube(5) ) // 125
console.log( m_multply(3,7) ) // 21
.as-console-wrapper { max-height: 100% !important; top: 0; }
the same with Alnitak method (with map)
function memoïze(func)
{
let cache = new Map()
return (...vals)=>
{
let key = JSON.stringify(vals)
if (!cache.has(key)) cache.set(key, func(...vals))
return cache.get(key)
} }

Checking if the characters in a string are all unique

I am trying to solve this problem using JS by just using an array.
var str = 'abcdefgh';
for (i = 0; i < 255; i++) {
arr[i] = false;
}
function check() {
for (i = 0; i < str.length; i++) {
if (arr[str.charCodeAt(i)] == true) {
return false;
}
arr[str.charCodeAt(i)] = true;
}
return true;
}
I am initializing an array of fixed size 256 to have the boolean value false.
Then i am setting the value for the corresponding ASCII index to true for characters in the string. And if i find the same character again, i am returning false.
While running the program, i am getting false returned even if the string doesn't have any duplicate characters.
Fill a Set with all characters and compare its size to the string's length:
function isUnique(str) {
return new Set(str).size == str.length;
}
console.log(isUnique('abc')); // true
console.log(isUnique('abcabc')); // false
Use object for faster result
function is_unique(str) {
var obj = {};
for (var z = 0; z < str.length; ++z) {
var ch = str[z];
if (obj[ch]) return false;
obj[ch] = true;
}
return true;
}
console.log(is_unique("abcdefgh")); // true
console.log(is_unique("aa")); // false
use .match() function for each of the character. calculate occurrences using length. Guess thats it.
(str.match(/yourChar/g) || []).length
We can also try using indexOf and lastIndexOf method:
function stringIsUnique(input) {
for (i = 0; i < input.length; i++) {
if (input.indexOf(input[i]) !== input.lastIndexOf(input[i])) {
return false;
}
}
return true;
}
You are using arr[str.charCodeAt(i)] which is wrong.
It should be arr[str[i].charCodeAt(0)]
var arr = [];
var str="abcdefgh";
for (i=0;i<255;i++){
arr[i]=false;
}
function check(){
for (i=0;i<str.length;i++){
if (arr[str[i].charCodeAt(0)]==true){
return false;
}
arr[str[i].charCodeAt(0)]=true;
}
console.log(arr);
return true;
}
check();
Time complexity = O(n)
Space complexity = O(n)
const isUnique = (str) => {
let charCount = {};
for(let i = 0; i < str.length; i++) {
if(charCount[str[i]]){
return false;
}
charCount[str[i]] = true;
}
return true;
}
const isUniqueCheekyVersion = (str) => {
return new Set(str).size === str.length;
}
Solution 3:
Transform string to chars array, sort them and then loop through them to check the adjacent elements, if there is a match return false else true
Solution 4:
It's similar to Solution 1 except that we use a Set data structure which is introduced in recent versions of javascript
// no additional Data structure is required. we can use naive solution
// Time Complexity:O(n^2)
function isUnique(str) {
for (let i = 0; i < str.length; i++) {
for (let j = 1 + i; j < str.length; j++) {
if (str[i] === str[j]) {
return false;
}
}
}
return true;
}
// if you can use additional Data structure
// Time Complexity:O(n)
function isUniqueSecondMethos(str) {
let dup_str = new Set();
for (let i = 0; i < str.length; i++) {
if (dup_str.has(str[i])) {
return false;
}
dup_str.add(str[i]);
}
return true;
}
console.log(isUniqueSecondMethos('hello'));
Use an object as a mapper
function uniqueCharacterString(inputString) {
const characterMap = {};
let areCharactersUnique = true;
inputString.trim().split("").map((ch)=>{
if(characterMap[ch]===undefined) {
characterMap[ch] = 1;
} else {
areCharactersUnique = false;
}
})
return areCharactersUnique;
}
Algo
*1. step -first string is ->stack *
*2.step-string covert to CharArray *
3. step - use iteration in array ['s','t','a','c','k']
4. step - if(beginElement !== nextElement){return true}else{return false}
Implement code
function uniqueChars(string){
var charArray = Array.from(string) //convert charArray
for(var i=0;i<charArray.length;i++){
if(charArray[i] !== charArray[i+1]){
return true
}
else{
return false
}
}
}
var string ="stack"
console.log(uniqueChars(string))
Time complexity
O(nlogn)
Algo
Counting frequency of alphabets. e.g. 'Mozilla' will returns Object{ M: 1, o: 1, z: 1, i: 1, l: 2, a: 1 }. Note that, the bitwise NOT operator (~) on -~undefined is 1, -~1 is 2, -~2 is 3 etc.
Return true when all occurrences appear only once.
Implement code
var isUnique = (str) => {
const hash = {};
for (const key of str) {
hash[key] = -~hash[key];
}
return Object.values(hash).every((t) => t === 1);
};
console.log(isUnique('Mozilla'));
console.log(isUnique('Firefox'));
Another alternative could be:
var isUnique = (str) => {
const hash = {};
for (const i in str) {
if (hash[str[i]]) return false;
hash[str[i]] = true;
}
return true;
};
console.log(isUnique('Mozilla'));
console.log(isUnique('Firefox'));
To make efficient one, you can use simple hash map
let isUnique = (s) => {
let ar = [...s];
let check = {};
for (let a of ar) {
if (!check[a]) {
check[a] = 1;
} else {
return false
}
}
return true;
}
alert("isUnique : "+isUnique("kailu"));
Time complexity & Space complexity
using ES6
let isUnique = (s)=>{
return new Set([...s]).size == s.length;
}
console.log("using ES6 : ",isUnique("kailu"));
We can use split method of string:
const checkString = (str) => {
let isUniq = true;
for (let i = 0; i < str.length; i++) {
if (str.split(str[i]).length > 2) {
isUniq = false;
break;
}
}
return isUniq;
};
console.log(checkString("abcdefgh")); //true
console.log(checkString("aa")); //false

Categories

Resources