Post

✨ Big O ✨ Let me take you on a visual introduction to what big O notation is in my new blog post: samwho.dev/big-o. With big O notation you can better understand how algorithms will perform in practice, finding orders of magnitude improvements often with very simple changes to your code.

105 reposts412 likes

Nothing is really stopping you from writing O(2n) if you really wanted to, but you won't find many people doing it. The idea is that as N approaches infinity, what is the most significant term? And in this case it is N itself. The multiplication doesn't change the _growth_ of the function.

> Note: On some browsers, you might experience bars taking a lot longer than they should It's true! I wonder why this happens. This could be a really fun rabbit hole

I only call sum once so I don’t think this technique applies. I’m running the code on a pool of web worker threads so there’s a bunch of overhead in posting messages back and forth and then with OS-level thread scheduling.

All of that pales in comparison to the fact Firefox sometimes takes 4-8x longer (e.g 8 seconds for the 2nd bar). Couldn’t for the life of me figure out why. Tried all sorts. Solar flares, innit.

And of course despite proof reading it no fewer than a dozen times personally, and having 4 calls with others to proof read it 1:1 with them, and sending it to maybe half a dozen other people over the last 2 months, someone points out within minutes an incorrect code example. 🫠 Fixed now.

Lol! That’s really funny. Given that it works in Chrome, Safari, and Firefox I’m inclined to think it’s probably a Zen bug. 🤔

Great post, as expected! 💯 I wonder about the buildList example, though. The time complexity analysis of the function seems to omit the .join() operation, which makes the big O value either O(n^2+n) or O(2n), right?

Technically yes, but big O only includes the most significant contributor to the function’s growth, and then the smallest variant of it. It’s very confusing. So O(n^2+n) is just O(n^2). The idea is to say “the order of growth is no less than this.” I do sometimes see people being more specific.

Right. I’ve seen examples with multiple components, signalling that an algorithm has multiple expensive operations to it (for example, in a gamedev book). In a case of two linear components, there is no clear winner, I guess?

Yeah, when comparing two algorithms of the same big O you have to use other tools like wall clock time. Big O is one of many tools for describing algorithms :)

nice post! i love the interactive graphs. there are a few things aren't correct here though. this is false. it's a common misconception, but it's still wrong. O and Θ can both be used to describe worst-case or average case complexities.

sorry, but that's still incorrect. Θ(n^2) is not about best case complexity, it means that the complexity of the algorithm is equivalent to n^2, whereas with O, it is only "at most as slow as" n^2, but it could be faster. so bubble sort's worst case complexity *is* in Θ(n^2)

the difference is that O is an upper bound (so e.g. n ∈ O(n^2)), whereas Θ is an upper *and lower* bound (f ∈ Θ(g) means f ∈ O(g) *and* g ∈ O(f)) in fact, you used O notation yourself to describe the *expected* complexity of hash sets! (the worst-case complexity is linear)

This was on purpose, I wanted to avoid talking about amortisation and figured this little fib wasn’t the end of the world.

oh to be clear: using O is correct here! if you wanted to be 100% exact you would have to write "O(1) expected time complexity", but in this case it's pretty common to leave that inferred.

this is another misconception. O(1) complexity only means that a function is *bounded* by a constant. it can still vary in fact, if you have a time complexity like T(n) = Σ_(i=1)^n (1/2)^i then T is strictly monotonically increasing, but it is still in O(1), because it will never exceed 2.

this is also slightly incorrect. a linear time complexity *is* in O(2n), it's just that O(2n) and O(n) are the same complexity class (they're literally the same set)

I’ve been programming for years, but I don’t have a math background so Big O notation always kinda went over my head (despite reading many articles on it when I was on the LeetCode grind). This finally helped it click for me - thank you for making this article! The illustrations are sooo nice

Honestly, I don’t. I have in the past made animations less motion heavy if the user has specific prefer-reduced-motion but no one has ever made a comment in favour of it or complaining when it’s missing so I’ve not done it for a few posts. Not a great policy but happy to work with people who need it

Sounds good to me mate. At least you have considered it and have accepted. Just asking cos it's something I think about haha and don't know if I'm being too pedantic.

Loving the interactive demos! In the `buildList` example, there’s no need to stop using `for-of` just to get access to the index. Try: for (const [index, item] of items.entries()) { output.push(`Item ${index + 1}: ${items[index]}`); } Smaller diff, might be easier to follow. WDYT?

I avoided this because it’s a JS-ism some folks might not be familiar with. I felt the index example was a bit more widely accessible ans achieved the same goal. I call out Object.entries under the last code example. 🙏

It is, yeah. Couldn’t figure out if I wanted to include it or not and ended up publishing without deciding, which is a decision of sorts.

I’m really glad to hear that! I try and write the post I would have wanted when I was learning, and I learn best thorough seeing and playing with examples. Love to hear that it resonated with you ❤️

Another fantastic post 😁 I love how well you distill these concepts into easy to understand and interactive articles. Looking forward to sharing this in my newsletter this week 😁