¯\_(ツ)_/¯
Indulge me in a brief anecdote, please.
Learning some computer science won't hurt your career. It augments your day-to-day working knowledge.
It also can help you pass technical interviews more often.
Hopefully, better jobs => better life.
"Big O Notation" is a standard way of describing the worst-case performance of an algorithm in regards to time and/or space.
Good question!
An algorithm is a procedure for solving a problem. That's it. Nothing scary. It's a step-by-step way of going from start to finish.
const foo = () => 'foo'
const first = arr => arr[0]
const prop = (key, obj) => obj[key]
const arr = [1, 2, 3, 4, 5]
arr.forEach()
arr.map()
arr.find()
arr.reduce()
const arr = [1, 2, 3, 4, 5]
const twoDArray = arr.map(n => arr.map(m => m * n))
console.log(twoDArray)
// [[1, 2, 3, 4, 5],
// [2, 4, 6, 8, 10],
// [3, 6, 9, 12, 15],
// [4, 8, 12, 16, 20],
// [5, 10, 15, 20, 25]]
const fib = n => {
if (n < 2) {
return 1
}
return fib(n - 1) + fib(n - 2)
}
const binarySearch = (value, tree) => {
const { left, right, value: rootValue } = tree.root
return value === rootValue
? root
: value < rootValue
? binarySearch(value, left)
: binarySearch(value, right)
}
We now recognize that certain data structures might be better suited for a task than others. One typical problem are find
s on lists. How can we overcome this?
// Create a normalizing function for IDs
const normalizeByID = arr => arr.reduce((acc, cur) => {
acc[cur.id] = cur
return acc
}, {})
const list = [
{ id: 1, name: 'Kyle' },
{ id: 2, name: 'Anna' },
{ id: 3, name: 'Krios' },
{ id: 4, name: 'Tali' }
]
console.log(normalizeByID(list))
// {
// '1': { id: 1, name: 'Kyle' },
// '2': { id: 2, name: 'Anna' },
// '3': { id: 3, name: 'Krios' },
// '4': { id: 4, name: 'Tali' }
// }
We traded space for time.
We changed finding an item by ID from of O(n) to O(1).
Memoization is the use of a cache within a function to store previously calculated results for retrieval. We trade space for the time cost of recalculating the result again.
const memo = fn => {
const cache = {}
return (...args) => {
const stringifiedArgs = args.join('')
if (cache[stringifiedArgs]) {
return cache[stringifiedArgs]
}
const result = fn(...args)
cache[stringifiedArgs] = result
return result
}
}
memo
accepts a function as an argumentReselect
uses memoization for faster state updatesA tree is a graph data structure comprised of nodes with any number of children and no cycles.
A graph is a data structure made up of nodes with "edges" between them. A cycle is when several nodes all point to one another.
A tree only has parent and child nodes, with no child nodes pointing to other child nodes.
Every website* in the world is a tree data structure
*I haven't visited them all, so don't quote me on this 😝<html>
<head>
<title>Learning Backwards</title>
</head>
<body>
<p>Ain't it <strong>awesome</strong> learning backwards!</p>
</body>
</html>
{
value: html,
children: [
{ value: head, children: [
{ value: title, children: ['Learning Backwards'] }
]},
{ value: body, children: [
{ value: p, children: [
"Ain't it ",
{ value: strong, children: ['awesome'] },
' learning backwards!'
]}
]}
]
}
React.createElement('html', {}, [
React.createElement('head', {}, [
React.createElement('title', {}, [
'Learning Backwards'
])
]),
React.createElement('body', {}, [
React.creactElement('p', {}, [
"Ain't it ",
React.createElement('strong', {}, [
'awesome'
]),
' learning backwards!'
])
])
])
const inOrderTraversal = visit => treeRoot => {
inOrderTraversal(visit)(treeRoot.left)
visit(treeRoot)
inOrderTraversal(visit)(treeRoot.right)
}
const inOrderTraversal = visit => treeRoot => {
visit(treeRoot)
inOrderTraversal(visit)(treeRoot.left)
inOrderTraversal(visit)(treeRoot.right)
}
const inOrderTraversal = visit => treeRoot => {
inOrderTraversal(visit)(treeRoot.left)
inOrderTraversal(visit)(treeRoot.right)
visit(treeRoot)
}