# Technical Interviews

By ACM

## What is a technical interview

• Generally 1-3 programming problems
• Problems are often algorithm focused
• Supposed to show how the candidate thinks

## Format

• Sometimes the interviewer might ask a few general/resume questions first
• Interviewer gives 1-3 programming problems
• Interviewer asks if the candidate has any questions
• Try to ask a couple of questions here, about company culture, average day, etc.

## What companies look for

• Communication
• Solving the problem correctly
• Thought process

(Disclaimer, we aren't recruiters and don't know how companies make decisons)

## Communication

• Discuss how you plan to solve the problem
• Let the interviewer know if you need to take some time to think about the problem

Try do mock interviews with friends (or ACM) to help practice this

## Solving the problem

• Practice interview problems
• Try practice without a computer sometimes
• Resources
• Leetcode.com
• Hackerrank.com
• Cracking the Coding Interview
• ACM workshops
• Practice problems later

## Thought process

• Companies say this is the most important part
• How do you approach the problem?
• Do you consider which data structures to use
• Do you consider edge cases
• Do you consider time complexity
• Do you create test cases and test your solution?
• Do you try check if there could be a better approach?

## Some tips

• Practice (On paper, ideally)
• Take the interviewers hints
• Plan out your solution before coding
• Don't chase a solution you've seen but can't remember

## General Precurser

• Time complexities
• Data structures

## Time Complexities

• O(n) =>
• O(n^2) =>
• Basic time complexities included below
``for(int i = 0; i < arr.size(); i++)``
``````for(int i = 0; i < arr.size(); i++)
for(int j = 0; j < arr.size(); j++)``````

## Data Structures

• Arrays
• Hash Maps/Sets
• Binary Trees
• Stacks
• Queues

# Problem #1

## 2 Sum

• Leetcode: https://leetcode.com/problems/two-sum/

• Given a list of integers and a value (v), return a list containing the 2 indices that sum to v.

• Ex: S = 7, list = [1, 2, 3, 4, 8, 11, 0].
• We would return [2, 3] because 3 and 4 sum to 7.

## Naive Solution

• This solution is O(n^2), but are we repeating any work?
• We are checking if i + j = S, can we change something so that we repeat work?

Text

``````def twoSum(arr, S):

sums = []

for i in range(0, len(arr)):
for j in range(i+1, len(arr)):

# Here we are only looking for a single pair,
# so we can return after we find it.
if (arr[i] + arr[j] == S):
sums.append(arr[i])
sums.append(arr[j])
return sums;

return None``````

## O(n) Solution

Text

``````def twoSum(arr, S):

sums = []
hashTable = {}

for i in range(0, len(arr)):
sumMinusElement = S - arr[i]

# Lets check if we have seen S - arr[i] before. If so, then we have a pair.

if sumMinusElement in hashTable:
sums.append(arr[i])
sums.append(sumMinusElement)
return sums

# Lets put arr[i] in the hash table so that if we get anther value j such
# that arr[j] + arr[i] = s, we check if we have seen arr[i] in O(1).

hashTable[arr[i]] = arr[i]

return None``````

# Problem #2

## Coin Change

• Leetcode: https://leetcode.com/problems/coin-change/
• Given a list of coins, determine the fewest number that can be used to create a target value

## Considerations

• What algorithm can we use
• How fast is it
• Does it work in every case

## Idea #1

• Greedy algorithm
• Take the biggest coin every time
• Does this always work?
• Test cases
• [1, 5, 10, 25], 18
• [1, 6, 7, 15], 12

## Idea #2

• Try every combination
• Basically guaranteed to work
• How fast is this?
• Exponential complexity

## Idea #2 Implementation

``````class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
#base cases
if amount == 0:
return 0
if amount <= 0:
return float('inf')
best = float('inf')
for c in coins:
best = min(best, self.coinChange(coins, amount-c))

#deal with some edge cases
if best == float('inf'):
return -1
if best == -1:
return best
return best+1``````

# Idea #3

## Two main requirements

• Overlapping sub-problems
• Optimal substructure
• This means that sub-problems can be combined to solve the main problem

## Why do we care

• Can often bring time complexity down from exponential to linear on difficult problems
• Commonly asked category in harder interviews

## How does this apply to coin change

• Example: [3,5,7], 16
• With out brute force solution the functions calls will look like this:

16

9

11

13

4

6

2

6

4

8

8

6

10

## Idea #3 Solution

``````class Solution:
def coinChangeH(self, coins: List[int], amount: int) -> int:
if amount in self.seen:
return self.seen[amount]

if amount == 0:
return 0
if amount <= 0:
return float('inf')
best = float('inf')
for c in coins:
best = min(best, self.coinChangeH(coins, amount-c))
if best == float('inf'):
self.seen[amount] = float('inf')
return float('inf')

self.seen[amount] = best+1
return best+1

def coinChange(self, coins: List[int], amount: int) -> int:
self.seen = {}
res = self.coinChangeH(coins, amount)
if res == float('inf'):
return -1
return res``````
• Some leetcode weirdness requires initializing seen in the main coinChange rather than making it global/member var

• Need to make sure to cache results of the failiures too

# Problem #3

## Traversing Trees

• Depth First Search
• Pre-order
• In-order
• Post-order

# Binary Tree Level Order Traversal

• Leetcode: https://leetcode.com/problems/binary-tree-level-order-traversal/
• Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level).

# BFS Solution

``````class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
if root == None:
return []
ret = [[]]
queue = []
queue.append(root)
queue.append(None)
level = 0
while len(queue) > 1:
node = queue
queue.pop(0)
if node == None:
ret.append([])
level+=1
queue.append(None)
else:
ret[level].append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return ret``````

#### Technical Interviews

By theasocialmatzah

• 64