Interview Basics
Interview Basics
Workshop
Jeremy Aguilon
Download this!
https://github.com/JerAguilon/TechnicalInterviewCodeSnippets
Interned
Student
My motivation
80%
of interview questions
1 hour
of learning
Curriculum Prerequisites
1. Sliding Window 1. Big-O
file: slidingWindow/slidingWindow.py
Problem example
Given a string and a set of characters, find the length of the smallest substring
that contains all of the characters
input: ABCZDACB, set: {A,B,C,D}
solution: DACB → 4
solution: A → 1
solution: CEBEA → 5
C) There may be many substrings that have all the characters and start and
end with different characters in the set
input: ABEEEEEECEBBEAEEEEEEBAGDC, set: {A, B, C}
Runtime: O(n)
Sliding Window Problem
Algorithm visualization
input: DADDDBBDCA, set: {A, B, C}
bestScore = infinity
encounteredCharacters {‘a’:0, ‘b’:0, ‘c’ :0, ‘d’:0}
D A D D D B B D C A
0 1 2 3 4 5 6 7 8 9
right
left
bestScore = infinity
encounteredCharacters {‘a’:0, ‘b’:0, ‘c’:0, ‘d’:1}
D A D D D B B D C A
0 1 2 3 4 5 6 7 8 9
right
left
bestScore = infinity
encounteredCharacters {‘a’:1, ‘b’:0, ‘c’:0, ‘d’:1}
D A D D D B B D C A
0 1 2 3 4 5 6 7 8 9
right
left
bestScore = infinity
encounteredCharacters {‘a’:1, ‘b’:0, ‘c’:0, ‘d’:2}
D A D D D B B D C A
0 1 2 3 4 5 6 7 8 9
right
left
bestScore = infinity
encounteredCharacters {‘a’:1, ‘b’:0, ‘c’:0, ‘d’:3}
D A D D D B B D C A
0 1 2 3 4 5 6 7 8 9
right
left
bestScore = infinity
encounteredCharacters {‘a’:1, ‘b’:0, ‘c’:0, ‘d’:4}
D A D D D B B D C A
0 1 2 3 4 5 6 7 8 9
right
left
bestScore = infinity
encounteredCharacters {‘a’:1, ‘b’:1, ‘c’:0, ‘d’:4}
D A D D D B B D C A
0 1 2 3 4 5 6 7 8 9
right
left
bestScore = infinity
encounteredCharacters {‘a’:1, ‘b’:2, ‘c’:0, ‘d’:4}
D A D D D B B D C A
0 1 2 3 4 5 6 7 8 9
right
left
bestScore = infinity
encounteredCharacters {‘a’:1, ‘b’:2, ‘c’:0, ‘d’:5}
D A D D D B B D C A
0 1 2 3 4 5 6 7 8 9
right
left
bestScore = infinity
encounteredCharacters {‘a’:1, ‘b’:2, ‘c’:1, ‘d’:5}
D A D D D B B D C A
0 1 2 3 4 5 6 7 8 9
right
left
bestScore = infinity
encounteredCharacters {‘a’:1, ‘b’:2, ‘c’:1, ‘d’:4}
D A D D D B B D C A
0 1 2 3 4 5 6 7 8 9
right
left
bestScore = infinity
encounteredCharacters {‘a’:0, ‘b’:2, ‘c’:1, ‘d’:4}
D A D D D B B D C A
0 1 2 3 4 5 6 7 8 9
right
left
D A D D D B B D C A
0 1 2 3 4 5 6 7 8 9
right
left
bestScore = 8
encounteredCharacters {‘a’:0, ‘b’:2, ‘c’:1, ‘d’:4}
D A D D D B B D C A
0 1 2 3 4 5 6 7 8 9
right
left
bestScore = 8
encounteredCharacters {‘a’:1, ‘b’:2, ‘c’:1, ‘d’:4}
D A D D D B B D C A
0 1 2 3 4 5 6 7 8 9
right
left
bestScore = 8
encounteredCharacters {‘a’:1, ‘b’:2, ‘c’:1, ‘d’:3}
D A D D D B B D C A
0 1 2 3 4 5 6 7 8 9
right
left
bestScore = 8
encounteredCharacters {‘a’:1, ‘b’:2, ‘c’:1, ‘d’:2}
D A D D D B B D C A
0 1 2 3 4 5 6 7 8 9
right
left
bestScore = 8
encounteredCharacters {‘a’:1, ‘b’:2, ‘c’:1, ‘d’:1}
D A D D D B B D C A
0 1 2 3 4 5 6 7 8 9
right
left
bestScore = 8
encounteredCharacters {‘a’:1, ‘b’:1, ‘c’:1, ‘d’:1}
D A D D D B B D C A
0 1 2 3 4 5 6 7 8 9
right
left
bestScore = 8
encounteredCharacters {‘a’:1, ‘b’:0, ‘c’:1, ‘d’:1}
D A D D D B B D C A
0 1 2 3 4 5 6 7 8 9
right
left
bestScore = 10 - 7 + 1 = 4
encounteredCharacters {‘a’:1, ‘b’:0, ‘c’:1, ‘d’:1}
D A D D D B B D C A
0 1 2 3 4 5 6 7 8 9
right
left
bestScore = 4
encounteredCharacters {‘a’:1, ‘b’:0, ‘c’:1, ‘d’:1}
currently: DONE!
D A D D D B B D C A
0 1 2 3 4 5 6 7 8 9
right
left
file: nestedIntervals/nestedIntervals.py
Problem example
Given a mathematical equation as a string, return whether or not the brackets are
appropriately balanced
input:{3*[1+5(6+8)]} input:{3*[1+5(6+8])}
input:{3*[1+5(6+8)]
solution: false
Nested Intervals
Observations
1. For every opening bracket, there has to be an
equivalent closing bracket
a. openingBrackets - closedBrackets = 0
2. Brackets can be nested, but there can’t be an “offset”
overlap: {(3+1})
Nested Intervals
Algorithm
A) Initialize an empty stack
B) Iterate over the equation. When an opening bracket is encountered, push
the character to the stack
C) If a closing character is encountered, the equation is valid if: the stack is not
empty and if the popped item in the stack matches the closing character
D) If C is never violated and the stack is empty after iterating, return true;
otherwise, return false
Runtime: O(n)
Nested Intervals
Algorithm visualization
input: (3 + 9{12 + 4})(25)
stack
( 3 + 9 { 1 2 + 4 } ) ( 2 5 )
curr
Nested Intervals
Algorithm visualization
input: (3 + 9{12 + 4})(25)
(
stack
( 3 + 9 { 1 2 + 4 } ) ( 2 5 )
curr
Nested Intervals
Algorithm visualization
input: (3 + 9{12 + 4})(25)
(
stack
( 3 + 9 { 1 2 + 4 } ) ( 2 5 )
curr
Nested Intervals
Algorithm visualization
input: (3 + 9{12 + 4})(25)
(
stack
( 3 + 9 { 1 2 + 4 } ) ( 2 5 )
curr
Nested Intervals
Algorithm visualization
input: (3 + 9{12 + 4})(25)
(
stack
( 3 + 9 { 1 2 + 4 } ) ( 2 5 )
curr
Nested Intervals
Algorithm visualization
input: (3 + 9{12 + 4})(25)
{
(
stack
( 3 + 9 { 1 2 + 4 } ) ( 2 5 )
curr
Nested Intervals
Algorithm visualization
input: (3 + 9{12 + 4})(25)
{
(
stack
( 3 + 9 { 1 2 + 4 } ) ( 2 5 )
curr
Nested Intervals
Algorithm visualization
input: (3 + 9{12 + 4})(25)
{
(
stack
( 3 + 9 { 1 2 + 4 } ) ( 2 5 )
curr
Nested Intervals
Algorithm visualization
input: (3 + 9{12 + 4})(25)
{
(
stack
( 3 + 9 { 1 2 + 4 } ) ( 2 5 )
curr
Nested Intervals
Algorithm visualization
input: (3 + 9{12 + 4})(25)
{
(
stack
( 3 + 9 { 1 2 + 4 } ) ( 2 5 )
curr
Nested Intervals
Algorithm visualization
input: (3 + 9{12 + 4})(25)
(
stack
( 3 + 9 { 1 2 + 4 } ) ( 2 5 )
curr
Nested Intervals
Algorithm visualization
input: (3 + 9{12 + 4})(25)
stack
( 3 + 9 { 1 2 + 4 } ) ( 2 5 )
curr
Nested Intervals
Algorithm visualization
input: (3 + 9{12 + 4})(25)
(
stack
( 3 + 9 { 1 2 + 4 } ) ( 2 5 )
curr
Nested Intervals
Algorithm visualization
input: (3 + 9{12 + 4})(25)
(
stack
( 3 + 9 { 1 2 + 4 } ) ( 2 5 )
curr
Nested Intervals
Algorithm visualization
input: (3 + 9{12 + 4})(25)
(
stack
( 3 + 9 { 1 2 + 4 } ) ( 2 5 )
curr
Nested Intervals
Algorithm visualization
input: (3 + 9{12 + 4})(25)
stack
( 3 + 9 { 1 2 + 4 } ) ( 2 5 )
curr
Nested Intervals
Algorithm visualization
input: (3 + 9{12 + 4})(25)
stack
( 3 + 9 { 1 2 + 4 } ) ( 2 5 )
curr
Nested Intervals
Pseudocode solution!
def solution(string):
stack = Stack()
for letter in string:
if isOpeningBracket(letter):
stack.push(letter)
else if isClosingBracket(letter):
if stack is empty:
return false
lastOpener = stack.pop()
if not matches(letter, lastOpener):
return false
return stack.isEmpty() *iterated successfully over the string, just
make sure that the stack has been cleared
Nested Intervals
Popular questions
A) Given a list of start and end times, return a list of
merged times:
[[1,6], [2,8],[10, 20]] → [[1,8],[10,20]]
*(item 0 and item 1 overlap)
hint: the starting interval values are like opening brackets and the
ending interval values are like ending brackets. Think about how you
can sort these endpoints.
Nested Intervals
Recursion: DFS
file: countingIslands/countingIslands.py
Problem example
Given a 2d grid, count the number of “islands” in the array. Land is represented as
a 1 that’s connected in the NSEW direction.
input: input: input:
1 1 0 1 0 0 1 1 1
1 0 0 0 1 0 1 0 1
0 1 0 0 0 1 0 1 1
2 3 1
Recursion: DFS
Observations
A) The grid is almost like a graph:
1 1 0 1 1
1 0 0
0 1 0
1
Recursion: DFS
Algorithm
1. Iterate over the array using a nested for loop w/ variables x and
y. If you encounter a 1, perform a depth-first-search (DFS)
traversal and increment the islandCount variable by 1
2. DFS search using recursion
a. Base Case: stop recursing if:
i. The index of x and y are out of bounds of the array
ii. The item at arr[x][y] is 0 (not land)
b. Recursive case:
i. Change the element at arr[x][y] to be 0, so that it is not
re-recursed on
ii. Call the recursive function on [x-1][y], [x+1][y], [x][y-1], and
[x][y+1]
Runtime: O(width*height)
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 0
x = 0 1 1 1
y = 0
1 0 0
currently: iterating
0 1 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 1 recX = 0
x = 0 recY = 0 1 1 1
y = 0
1 0 0
currently: recursing
0 1 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 1 recX = 0
x = 0 recY = 0 0 1 1
y = 0
1 0 0
currently: recursing
0 1 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 1 recX = 1
x = 0 recY = 0 0 1 1
y = 0
1 0 0
currently: recursing
0 1 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 1 recX = 1
x = 0 recY = 0 0 0 1
y = 0
1 0 0
currently: recursing
0 1 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 1 recX = 2
x = 0 recY = 0 0 0 1
y = 0
1 0 0
currently: recursing
0 1 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 1 recX = 2
x = 0 recY = 0 0 0 0
y = 0
1 0 0
currently: recursing
0 1 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 1 recX = 2
0 0 0 all
x = 0 recY = 0
recursive
y = 0
calls
1 0 0 terminate!
currently: recursing
0 1 0
curr
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 1 recX = 1
x = 0 recY = 0 0 0 0
y = 0
1 0 0
currently: recursing
0 1 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 1 recX = 0
x = 0 recY = 0 0 0 0
y = 0
1 0 0
currently: recursing
0 1 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 1 recX = 0
x = 0 recY = 1 0 0 0
y = 0
1 0 0
currently: recursing
0 1 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 1 recX = 0
x = 0 recY = 1 0 0 0
y = 0
1 0 0
currently: recursing
0 1 0
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 1 recX = 0
x = 0 recY = 1 0 0 0
y = 0
0 0 0
currently: recursing
0 1 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 1
x = 0 0 0 0
y = 0
0 0 0
currently: iterating
0 1 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 1
x = 1 0 0 0
y = 0
0 0 0
currently: iterating
0 1 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 1
x = 2 0 0 0
y = 0
0 0 0
currently: iterating
0 1 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 1
x = 0 0 0 0
y = 1
0 0 0
currently: iterating
0 1 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 1
x = 1 0 0 0
y = 1
0 0 0
currently: iterating
0 1 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 1
x = 2 0 0 0
y = 1
0 0 0
currently: iterating
0 1 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 1
x = 0 0 0 0
y = 2
0 0 0
currently: iterating
0 1 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 1
x = 1 0 0 0
y = 2
0 0 0
currently: iterating
0 1 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 2 recX = 1
x = 1 recY = 2 0 0 0
y = 2
0 0 0
currently: recursing
0 1 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 2 recX = 1
x = 1 recY = 2 0 0 0
y = 2
0 0 0
currently: recursing
0 0 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 2 recX = 1
0 0 0 all
x = 1 recY = 2
recursive
y = 2
calls
0 0 0 terminate!
currently: recursing
0 0 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 2
x = 1 0 0 0
y = 2
0 0 0
currently: iterating
0 0 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 2
x = 2 0 0 0
y = 2
0 0 0
currently: iterating
0 0 0
Recursion: DFS
Algorithm visualization
input: [[1,1,1], [1,0,0], [0,1,0]]
total = 2
x = 2 0 0 0
y = 2
0 0 0
currently: iterating
0 0 0
return 2
Recursion: DFS
Pseudocode solution!
def solution(arr):
total = 0
for y from 0 to length(arr):
for x from 0 to length(arr[y]):
if arr[x][y] == 1:
total += 1
dfs(x, y, arr)
return total
Recursion: DFS
Pseudocode solution!
def dfs(x, y, arr):
* base cases
if x < 0 or x >= length(arr) or y < 0 or y >= length(arr):
return
if arr[x][y] == 0:
return
* recursive case
arr[x][y] = 0
dfs(x+1, y, arr)
dfs(x-1, y, arr)
dfs(x, y-1, arr)
dfs(x, y+1, arr)
Recursion: DFS
Popular questions
A) Given a 2d grid of characters and a string, return
whether the word exists in the grid using the same rules
as the example question (can only recurse in the NSEW
direction, can’t re-use a cell)
a) Bonus: given a set of words, return whether all the words are in the
grid or not
Recursion: DFS
Other recursive questions
A) Given an array of integers, count the number of
inversions in it. The number of inversions is the number
of adjacent swaps necessary to sort the array.
Recursion: DFS
Dynamic
Programming
file: dynamicProgramming/dynamicProgramming.py
What is it?
Dynamic programming:
Dynamic Programming
Problem example
Given a number n representing total cents and a set of numbers
representing coins how many ways can you make n cents? You have
an infinite supply of each coin.
solution:
15 pennies
2 nickels, 5 pennies
1 nickel, 10 pennies
3 nickels
4 ways
Dynamic Programming
Attempt #1: Recursion
We can recursively reduce n until n<=0
base cases
n = 0 → return 1
n < 0 → return 0
recursive case
total = 0
for every coin c less than or equal to the last used coin:
total += recursivelySolve(n-c, coins, c)
return total
Effectively, we are recursing on two cases: for any coin ci, generate solutions
including ci and excluding ci
Dynamic Programming
Attempt #1: Python
def solve(n, coins, curr_coin_index):
* base cases
if n == 0:
return 1
if n < 0:
return 0
* recursive case
total = 0
for i in range(0, curr_coin_index):
total += solve(n - coins[i], coins, i)
return total
Dynamic Programming
Attempt #1: Recursive Tree
input: n=15 coins={1,5} n=7
penny
n=8
penny
n=9
(several)
pennies
n = 15 n=8
penny
nickel n=9
penny
n = 10 n=4
nickel penny
n=5
nickel
n = 0 return 1
Dynamic Programming
Attempt #1: Recursive Tree
input: n=15 coins={1,5} n=7
penny
n=8
penny
n=9
Dynamic Programming
Attempt #1: Recursive Tree
input: n=15 coins={1,5} n=7
penny
n=8
penny
n=9
(several)
pennies
n = 15 n=8
penny
How can we nickel n=9
reduce these penny
overlapping n = 10 n=4
problems? nickel penny
n=5
nickel
n = 0 return 1
Dynamic Programming
Memoization Yes, it’s really spelled that way
Dynamic Programming
Runtime analysis
● Depth of the tree: O(n) cache = {}
○ O(n) solutions are computed def solve(n, coins, curr_coin_index):
due to caching * base cases
if n == 0:
● Each subproblem requires return 1
O(len(coins)) iterations if n < 0:
return 0
if (n, curr_coin_index) in cache:
time complexity: O(n*len(coins)) return cache.get((n, curr_coin_index))
* recursive case
● Number of items in the total = 0
for i in range(0, curr_coin_index):
cache: O(n) total += solve(n - coins[i], coins, i)
Dynamic Programming
Popular questions
Optimize the fibonacci recursive function.
Given a n*n matrix where all numbers are distinct, find the
maximum length path (starting from any cell) such that all
cells along the path are in increasing order with a
difference of 1. You can traverse in the NSEW direction.
Dynamic Programming
return;
That’s all! What next?