Solving Problems with JavaScript - mchaitanya/algorithms_practice GitHub Wiki
Solving Problems with JavaScript
Standard built-in objects
- -Infinity/+Infinity - can be useful to initialize a min/max variable
Note: Number.MIN_VALUE is the number closest to 0, not the most negative number, that JavaScript can represent. - Math
Math.min
/Math.max
Math.abs
/Math.sign
Math.random
- returns a pseudorandom number between 0 and 1
- BigInt - special numeric type that provides support for integers of arbitrary length
- Number
parseInt(string, [radix])
- to convert a numeric string to numbertoString([radix])
- to convert a number of a string, where2 <= radix <= 36
- Date
new Date(year, monthIndex, day)
// monthIndex is zero-basedDate.prototype.getDay
// return day of the week (0-6)
- Array
- use as a stack with push() & pop()
- use as a queue with push() & shift()
Array(arrayLength)
- can be useful if we know how big the array will be, better than starting empty and pushing
this implies an array of arrayLength empty slots, not slots with actual undefined values [calling say
map
on the result ofArray(arrayLength)
doesn't do anything, fill it first with 0]- Be careful with
Array.prototype.fill
- if you give it an object, each slot in the array will reference that object - sort an array in place with
arr.sort([compareFn])
- callingarr.sort()
on an array of numbers may not produce the right result
The default sort order is ascending, built upon converting the elements into strings, then comparing their sequences of UTF-16 code units values.
- String
String.prototype.charCodeAt(index)
// maps a character to its UTF-16 codeString.fromCharCode(number)
// converts UTF-16 code back to character, also note this is a 'class method'String.prototype.padStart(targetLength [, padString])
// can be useful when working with numbers as strings etc.String.prototype.localeCompare(compareString)
- useful when sorting an array of stringsregexp.test(str)
- ex:/[0-9a-z]/.test(char)
to check if a char is alphanumeric
- Map, API reference:
Map()
- can initialize a map with
Map(['key1', 'value1'], ['key2', 'value2'](/mchaitanya/algorithms_practice/wiki/'key1',-'value1'],-['key2',-'value2'))
Map.prototype.size
Map.prototype.has(key)
Map.prototype.get(key)
Map.prototype.set(key, value)
Map.prototype.delete(key)
- iterate over a map with
Map.prototype.keys()
,Map.prototype.values()
,Map.prototype.entries()
- iterates its elements in insertion order
- Set
Set()
- can initialize a set with
Set(array)
; Set.prototype.size
Set.prototype.has(value)
Set.prototype.add(value)
Set.prototype.delete(value)
- Heap - not available in the language, check implementation in the lib folder
Helpful syntax
- There's an exponentiation operator - a**b; don't calculate powers with loops
- Use optional chaining. Use in conjunction with the nullish coalescing operator. Most runtimes will support these operators.
// say, n1 & n2 are linked-list nodes
while (n1 != null || n2 != null) {
// instead of `val1 = (n1 == null ? 100 : n1.val)`
// use the nullish coalescing operator, otherwise you might end up with the default if val is 0
let val1 = n1?.val ?? 100;
let val2 = n2?.val ?? 100;
// ...
n1 = n1?.next;
n2 = n2?.next;
}
- Swap values with destructuring assignment - one liner that doesn't require a temp variable
let arr = [1, 2, 3, 4];
[arr[0], arr[1]] = [arr[1], arr[0]]; // swap 0th & 1st elements
- Use default values for function arguments
- Write a quick IIFE to do any recursive processing, example:
(function dfs(node, depth = 0) {
if (node != null) {
dfs(node.left, depth+1);
dfs(node.right, depth+1);
}
})(root);
- Can use an array as an object property, see Working with Objects
all keys in the square bracket notation are converted to string unless they're Symbols
const seen = {};
seen[0,0](/mchaitanya/algorithms_practice/wiki/0,0) = true; // to keep track of seen cells in a grid, say
- Break out of nested loops with a labeled break statement
bfs:
while (level.length > 0) {
for (let [r,c] of level) {
if (r === rt && c === ct) break bfs;
}
}
- Use a generator to traverse/scan the solution space. They're also useful in modularizing the code - decoupling how values are produced from how they are processed.
function *getPrimes() {
const seen = [];
search:
for (let num = 2; ; num++) {
for (let prime of seen) {
if (num % prime === 0) {
continue search;
}
}
seen.push(num);
yield num;
}
}
Console API
- When doing DFS on a tree, wrap each recursive call with a
console.group(node.val)
&console.groupEnd()
to visualize the tree. - Use
console.table(grid)
to visualize the state of a 2-d grid.