Module 2 Workbook
Module 2 Workbook
Module 2 Workbook
This week, we’re going to develop your coding interview strategy. The exercises in this
workbook are designed to help you practice each step of the process and reinforce the skills.
It’s important to realize that some of this may feel uncomfortable at first. You’re learning a
brand new skill that is likely different from how you’ve approached interviewing in the past.
Therefore, it’s really important that you just follow along and do the best you can. If you’re
getting frustrated, just take a few minutes away and come back to the exercises later. As you
get more practice, they will get easier and you’ll be glad that you put in the effort.
Throughout this workbook, we will be referring back to the steps of your problem solving
strategy. For reference, here are the steps:
Table of Contents
Day 1 . . . . . . . . . . . . . . . . . . . . . . . page 2
Day 2 . . . . . . . . . . . . . . . . . . . . . . . page 3
Day 3 . . . . . . . . . . . . . . . . . . . . . . . page 5
Day 4 . . . . . . . . . . . . . . . . . . . . . . . page 6
Day 5 . . . . . . . . . . . . . . . . . . . . . . . page 8
Day 6 . . . . . . . . . . . . . . . . . . . . . . . page 10
Day 7 . . . . . . . . . . . . . . . . . . . . . . . page 12
Today we will focus on Step 1 of our problem solving strategy: Understanding the problem.
1. Write down your assumptions about the problem. What, if anything, are you assuming
about the input or output? Were you given any specific information (ie. the input is
sorted)?
2. Work through the given examples. Verify how these inputs actually lead to the desired
output.
3. Write at least 2 sample inputs of your own and test them. Try to write tests that will hit
on potential edge cases.
4. Write the function signature. Be sure to define the type of the input and the output. If
you're using a dynamically typed language, you should still be clear on the expected
input and output type.
NOTE: Make sure you write down your answers somewhere. We are going to refer back to these
problems and complete the rest of the problem later this week.
Problems:
NOTE: It may feel like we’re jumping around a lot but there are 2 specific reasons for this. 1) It makes
sure that you’re really learning each individual skill. 2) It is important that you learn to clearly
articulate yourself. By having to remember from day to day what you’ve been working on, you
improve your ability to be clear.
Part 1:
Part 1 we’re going to do exactly what we did yesterday. Do the following for each problem:
1. Write down your assumptions about the problem. What, if anything, are you assuming
about the input or output? Were you given any specific information (ie. the input is
sorted)?
2. Work through the given examples. Verify how these inputs actually lead to the desired
output.
3. Write at least 2 sample inputs of your own and test them. Try to write tests that will hit
on potential edge cases.
4. Write the function signature. Be sure to define the type of the input and the output. If
you're using a dynamically typed language, you should still be clear on the expected
input and output type.
Problems:
Once you've done the first part, we're going to start coming up with brute force solutions to
some of the problems that you did yesterday.
For each of the problems below, come up with a basic brute force solution. There's no need to
code it up fully, but write enough pseudocode that you will be able to refer back to it and
remember what you were doing.
As a reminder, here are some of the things we talked about in class when finding a brute force
solution:
For each of the problems below, come up with a basic brute force solution. There's no need to
code it up fully, but write enough pseudocode that you will be able to refer back to it and
remember what you were doing.
As a reminder, here are some of the things we talked about in class when finding a brute force
solution:
Part 2:
Today we're going to start working on Step 3, optimizing our solutions. This part is going to
start to get more time consuming so we'll start with just one problem.
For this problem, consider how we can optimize our brute force solution. You should complete
the following steps:
For each of the problems below, come up with a basic brute force solution. There's no need to
code it up fully, but write enough pseudocode that you will be able to refer back to it and
remember what you were doing.
As a reminder, here are some of the things we talked about in class when finding a brute force
solution:
Today we're going to start working on Step 3, optimizing our solutions. This part is going to
start to get more time consuming so we'll start with just one problem.
For this problem, consider how we can optimize our brute force solution. You should complete
the following steps:
For each of the problems below, come up with a basic brute force solution. There's no need to
code it up fully, but write enough pseudocode that you will be able to refer back to it and
remember what you were doing.
As a reminder, here are some of the things we talked about in class when finding a brute force
solution:
Today we're going to start working on Step 3, optimizing our solutions. This part is going to
start to get more time consuming so we'll start with just one problem.
For this problem, consider how we can optimize our brute force solution. You should complete
the following steps:
Today we're going to start working on Step 3, optimizing our solutions. This part is going to
start to get more time consuming so we'll start with just one problem.
For this problem, consider how we can optimize our brute force solution. You should complete
the following steps:
Yay time for some actual coding. Be very aware of how long it takes for you to code up each
one of these problems. If you did the previous step correctly it shouldn't take you more than 15
minutes. If not, then you'll want to focus on better understanding the problems in the future.
● Code up the entire solution by hand. DO NOT look anything up. If you forget the function
definition, just put a placeholder or best guess.
● Once you think your code is correct, test it by hand.
● If it works, then and only then, copy it verbatim into an IDE or Leetcode and try to run
your code.
● Make a list of all the errors in your code to refer back to later.
Problems:
We’ve done a lot this week so I didn’t schedule anything for you on this last day. Use this time
to take a little break or catch up on anything you may have gotten behind on :)
5. Maximum Binary Tree Depth (Leetcode, Video Walkthrough, Java Code, Python Code)
a. Assumptions:
i. The max depth is the number of nodes
ii. The min depth is log(number of nodes)
iii. Input is the root node of the tree
iv. Can probably do some sort of DFS or BFS
v. Just need to find the length of the longest path
b. Function Definition: int maxDepth(TreeNode root)
1. Linked List Cycles (Leetcode, Video Walkthrough, Java Code, Python Code)
a. Assumptions:
i. There may or may not be a cycle at all
ii. Multiple nodes can have the same value so we should compare objects
and not values
iii. Single-directional linked list
b. Function Definition: boolean hasCycle(ListNode head)
2. Buy and Sell Stock (Leetcode, Video Walkthrough, Java Code, Python Code)
a. Assumptions:
i. Only one transaction per day
ii. A buy transaction has to be followed by a sell transaction - can we group
them?
iii. Only one transaction -> want to find the biggest difference
b. Function Definition: int maxProfit(int[] prices)
Part 2:
1. Maximum Sum Subarray (Leetcode, Video Walkthrough, Java Code, Python Code)
a. Brute force solution: The easiest approach here is just to compare all of the
different subarrays and find the one that has the maximum sum. Remember that
often our approach can just involve enumerating all the possibilities, particularly
when a problem asks for the best solution.
2. Number of Islands (Leetcode, Video Walkthrough, Java Code, Python Code)
a. Brute force solution: We can do a variant of either BFS or DFS here. It doesn't
really matter which one we choose. We can just start at each different position
on the map and expand out as much as we can from there to find a single island.
Then we repeat this for all of the unvisited areas of the map.
Part 1:
Part 2:
1. Maximum Sum Subarray (Leetcode, Video Walkthrough, Java Code, Python Code)
a. Time Complexity
i. There are n2 different subarrays
ii. It takes O(n) time to compute the sum
iii. n2 * O(n) => O(n3)
b. Space Complexity
i. We don’t require any extra space
ii. O(1)
c. Best Conceivable Runtime
i. At minimum we have to visit all of the values in our array
ii. Our array is length n
iii. O(n)
d. Best Conceivable Space
i. We are already O(1)
e. Optimization approaches
i. Can we do this without looking at all the subarrays?
ii. Is there a way we can avoid visiting the same value multiple times?
iii. Can we avoid having to recompute the sum every time?
iv. Could we use a running sum?
v. Could we use a sliding window?
1. Maximum Binary Tree Depth (Leetcode, Video Walkthrough, Java Code, Python Code)
a. Brute force solution: This is another DFS problem. If we just enumerate all the
paths in the tree, we can select whichever is the longest one.
2. Linked List Cycles (Leetcode, Video Walkthrough, Java Code, Python Code)
a. Brute force solution: The easiest solution here is to track all the nodes we've
seen so far. We can add them all to a set. Then we'll just check each time we
visit a node whether or not we've seen it before. The question is whether we can
do this without extra space.
Part 2:
1. Buy and Sell Stock (Leetcode, Video Walkthrough, Java Code, Python Code)
a. Brute force solution: We're only able to buy and sell once, so let's just look at
every possible buy-sell combination.
Part 2:
1. Maximum Binary Tree Depth (Leetcode, Video Walkthrough, Java Code, Python Code)
a. Time Complexity
i. We are doing a search in our tree
ii. We have to consider all possible paths, and therefore we have to visit
every node
iii. O(n)
b. Space Complexity
i. We are searching recursively and the maximum depth of our recursion is
n
ii. We aren’t using any other space
iii. O(n)
c. Best Conceivable Runtime
i. We’re going to have to visit all the nodes in the worst case so there isn’t
any improvement to be had here
ii. O(n)
d. Best Conceivable Space
i. If we are doing DFS or BFS, we are going to need to use extra space
ii. O(n)
e. Optimization approaches
i. In this case, there’s not really any optimization we can do
f. Plain-English solution
i. We will use DFS to traverse each path in the tree
ii. As we traverse, we will count the length of the path and keep track of the
longest path we have seen
iii. Finally, we just return the length of the longest path
In the first case, it is clear that the pointers will point to the same node in
the next step. In the second case, by taking one step forward, you end up
with case #1.
Part 2: