Home > Reflections | ⏮️ ⏭️
2024-06-24
🏋️ Coding Practice
199. Binary Tree Right Side View
Given the
root
of a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.
🪞 Reflections
- This is a very similar problem to what I saw in a real interview about a week ago
- that previous exposure seems to have been enough for a flawless performance today
- < 21 minutes isn’t bad for a medium problem
- manually testing recursive functions is still a bit cumbersome
- representing trees in manual tests is still a bit cumbersome
- running 2 manual tests seemed like a good strategy here
- the first was for good coverage of a tricky case (a tree where the rightmost node was sometimes in a left branch
- the second was a simple null test, covering a common edge case
- having a 3rd check, explicitly for null checks didn’t take much time and seems valuable to incorporate into my general strategy
- This pass reminds me of static analysis: it takes less time to do than a dynamic test, we pay attention to fewer things, it’s good for catching limited classes of bugs
- I wonder if there are other classes of manual “static analysis” that would be useful to incorporate
- Perhaps a manual type checking phase could be useful, where I ensure that I’m using values according to their types. This seems like good motivation to add more explicit type annotations to my code.
- While I forgot to annotate the time required for planning, it didn’t take long. Seems like a good balance of succinct yet thorough enough to get the main ideas in place (though I didn’t explicitly call out recursion in my plan… perhaps because I was already anticipating using this based on prior exposure to a very similar problem) and support proper big-O complexity analysis.
- A second pass to refactor and simplify yielded a much shorter, simpler implementation.
- Implementing the iterative version is good practice
- in the iterative loop, push on the stack in reverse order to recursive calls from the recursive version
- refactorings from the recursive version can be mapped to analogous refactorings in the iterative version
- The bug found in the iterative version should have been caught by my test.
- I must have been mentally popping elements off of the stack in the order I wanted them to come out in (i.e. sometimes from the top and sometimes from the bottom) instead of the order dictated by the code.
- 🤔 I wonder what the appropriate systematic compensation is for this kind of error.
- Maybe I was a bit too loose with my test state annotations, relying too heavily on my working memory and mental shortcuts.
- Or maybe I was simply too quick to assume the result of the
.pop()
operation, and to compensate I should habitually be more dilligent about simulating operations instead of taking mental shortcuts. - Or maybe this error is best thought of as a bit of random variation to be expected in the long run and the current speed to rigor ratio is appropriate for interview contexts. i.e. common cause variation and not special cause variation.
- Extra type annotations don’t take much time to write and seem like a helpful addition to my usual routine (in support of an occasional type-checking, manual, static-analysis pass).
- Reviewing the official solutions after implementing my ideas yielded some approaches I hadn’t considered and inspired mutation-minimizing implementations.