Home > Reflections | ⏮️ ⏭️

2024-06-18

🧠 Education

🧰 3 High Leverage Career Skills (From a Principal At Amazon)
💸 Principal Engineer Reveals How To Be Promoted FAST

🔮 Interview Preparation Planning

My top 3 priorities moving forward:

  1. Reconstruct a brag document of recent accomplishments in my career.
    1. Priorities: stories about broad, cross-team impacts and conflict resolution
    2. Fill in concrete details
    3. Form stories, perhaps using the “man in a hole” U-shaped story structure
  2. Practice applying a design interview framework & seek feedback
  3. Continue practicing coding problems

I should also start setting up interviews with more companies, perhaps interleaving top tier companies that I’d love to work for with lower tier companies that will offer good interview practice whether I ultimately want to work there or not.

🏋️ Coding Practice

100. Same Tree

Given the roots of two binary trees p and q, write a function to check if they are the same or not.
Two binary trees are considered the same if they are structurally identical, and the nodes have the same value.

🪞 Reflections

  1. This went very well, finishing in under 10 minutes (though it is labeled an Easy problem)
  2. I’m happy with not spending too much time in the planning phase
    1. I quickly identified a high-level approach (adapting a traversal algorithm)
    2. I recognized the value of recursion here and identified it quickly
    3. I noted the complexity
    4. I finished in under 2 minutes, which is the guidance I’ve been offered for easy problems
  3. My solution came out pretty quickly, cleanly, and intuitively
  4. Testing recursive functions manually is a bit tedious
    1. I used a simplified version of the tree annotation that I typically used, which is better than using long-form attribute names
    2. I should probably practice using an even simpler short-hand for annotating trees during manual testing. I’ve seen them annotated as lists in plenty of example problems. That may be worth trying more consistently.
    3. I also didn’t bother writing both arguments, as they were identical. It’s good not to give myself too much busy work in the form of perfect test state annotation. This is a time management principle and focuses on doing what’s helpful and avoiding anything that’s not. Maybe an 80/20 situation.
    4. I only used a single test case, and it was only the positive case.
      1. I should probably have gone for a negative test case, too.
      2. I decided to review my code once more after testing and before submitting it.
        1. It’s good that I did, because I think I would have encountered null pointer exceptions had I not.
        2. Using a negative test case probably would have caught those, too. It’s nice to have a process that catches bugs in a more automatic fashion. I should probably chalk my catching of the null checks up to luck and work to incorporate more rigorous testing habits into my routine.
        3. For example, choosing a smaller test case, as already mentioned, is probably good form - especially if I’m ahead of time as I was here.
        4. Also, explicitly looking for potential null pointer exceptions seems like a useful step to incorporate on its own.
  5. I’m explicitly choosing tree problems to work with, as I felt uncomfortable with the tree problem I was given in my real interview yesterday.
    1. I think I solved the problem eventually.
    2. But I struggled more than I needed to, and should take the sign as a warning to focus more in this area.
  6. Just prior to working on this problem, I identified coding practice as third in my list of priorities.
    1. Arguably, this is fine, but I should be careful not to spend too much time in coding land before giving my behavioral and design skills the attention they deserve.

⌨️ My Solutions

/* determine if 2 binary trees are identical  
1. Seems like a pretty straight-forward adaptation of any recursive tree traversal algorithm will work out here  
  
Runtime complexity: O(N)  
Extra space complexity: O(N) (recursion involves memory overhead for each recursive call)  
[1:48] done planning  
[3:34] done with initial implementation  
[7:14] done with 1 test  
After testing, inserted 2 more null related checks  
[9:40] success on first submission  
  
*/  
/**  
 * Definition for a binary tree node.  
 * class TreeNode {  
 *     val: number  
 *     left: TreeNode | null  
 *     right: TreeNode | null  
 *     constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {  
 *         this.val = (val===undefined ? 0 : val)  
 *         this.left = (left===undefined ? null : left)  
 *         this.right = (right===undefined ? null : right)  
 *     }  
 * }  
 */  
  
function isSameTree(p: TreeNode | null, q: TreeNode | null): boolean { // null; { v: 3 }; { v: 2, r: { v: 3 } } }; { v: 1, l: { v: 2, r: { v: 3 } } } { v: 1, l: { v: 2, r: { v: 3 } } }  
  if (p == null && q == null) return true // true  
  if (p && !q) return false  
  if (q && !p) return false  
  if (p.val !== q.val) return false  
  if (!isSameTree(p.left, q.left)) return false // null; { v: 2, r: { v: 3 } } }  
  if (!isSameTree(p.right, q.right)) return false // null; { v: 3 }  
  return true  
};