# Effective Interview

copyright@ coding666.com

This is an instruction for an effective coding interview. Remember, the interviewer's only purpose is to help candidates get the best performance. So make friends with them to pass the interview.

# Timeline

The timeline at different tech companies are different. For example, Google interview usually contains only one question, with possible follow ups, while a Facebook interviewer always asks two questions, etc. This blog takes the Google interview as an example and for other interviews with more questions, just divide the time expectations by the number of questions.

# 3-5 min

Both interviewer and interviewee join the meeting, interviewer might greet you, ask a bit about your background. This is to help candidates calm down because every candidate is more or less nervous.

# 5-10 min

Interviewer gives a problem. The problem is usually vague. Candidate is expected to ask clarification questions. Ask as many as necessary to understand the requirements.

# 10-15 min

Candidate is expected to propose a workable solution, describe it clearly with the interviewer. The interviewer might ask clarification questions, ask for a better solution, or point out some defects in the algorithm. This step can be short as 2min or long as 10min. But do not get stuck here. The latest time for the next step (implementation) is at 20min. It's very rare that a candidate starts coding at 25min and can still pass the interview.

# 15-30 min

Candidates use ~15min to finish code implementation, pick up a few unit test cases, walk through the code and clear possible bugs in the code.

# 30-40 min

Further discussion between the interviewer and the candidate for time and space complexity of the solution, possible improvements, follow-ups, etc.

# 40-45 min

Wrapping up and the candidate can ask any question about the interviewer's work (usually not recorded into the final report).

As an interviewer, I usually want to stick to this timeline so that the candidate can have a working code / some code there at the end of the interview. So usually at some time checkpoints, I will give prompts / hints to facilitate the interview process. For example, if at 10min, the candidate is still asking clarification questions (most of the time those are meaningless ones). I'll ask them to start thinking about a solution. If a candidate cannot provide a workable solution by 20min, I'll start giving hints, or provide the steps to do the problem and ask them to do the implementation.

# Key Steps

I will use the famous two sum problem (opens new window) to explain some key steps and how effective communication can be established.

# Taking notes

It's always a good habit to document things. Remember, everything you typed on the shared doc with the interviewer will be recorded and presented to the hiring committee. So keeping notes of your discussion with the interviewer is a good way. This applies to the clarification questions, proposed steps, unit test cases, time / space complexity. With notes, the interviewer can see your thoughts more clearly and make comments on them instead of repeating your words.

# Problem clarification

The problem is designed to be vague. So the candidate is expected to ask clarification questions. Remember, it's always good to keep notes of these. An example note can be like this:

'''
input number range: [-10000, 10000]
can input be empty: yes
etc ...
'''

# Propose algorithm

Next the candidate needs to propose a working solution to the interviewer. It's recommended to use an example and show how the states are changed when the algorithm is applied. For example, the note can be:

'''
d: a dictionary to store number and its index
nums: [5, 3, 4], target: 7
d: {5: 0, 3: 1} -> return [1, 2]
'''

As shown in the example here, it's good to list the key state (the hashmap d here) of your algorithm and show that as you process a new number, how that state mutates. It's also good to mention the time and space complexity of the proposed algorithm.

# Implement the code

After the candidate reviews the algorithm with the interviewer, the candidate can confirm with the reviewer that they can start implementation. The implementation of this two sum problem is trivial.

def two_sum(nums: List[Int], target: Int) -> List[Int]:
  d = {}
  for idx, n in enumerate(nums):
    if target - n in d:
      return [d[target - n], idx]
    d[n] = idx

Now the candidate should not claim victory yet. They are supposed to list a few unit test cases and use them to validate the solution. This step is often skipped by most candidate, but it can show that

  • you care about the quality of the code
  • you know the workflow and structure of your code
  • you have strong debugging ability
  • you know how to do unit test
  • your code is rock solid When writing a unit test, it's good to
  • start with simple case, like in this two sum problems - empty nums, one element nums, two element nums, three element nums
  • cover as many case as possible - nums with duplicate values (e.g. nums = [1, 1], target = 2), input without a solution (such as nums = [1, 2], target = 4). The unit test part can largely distinguish an experienced engineer and entry level candidate.

It is also a good idea to put down some artifacts when proposing the test cases, and using comments to show the changes of key states (the d variable in this example) when walking through the code. The code in the end should look like this:

def two_sum(nums: List[Int], target: Int) -> List[Int]:
  d = {}
  for idx, n in enumerate(nums):
    if target - n in d:
      return [d[target - n], idx]
    d[n] = idx  # d: {1: 0}

'''
unit test cases:
[], 0
[1], 0
[1, 2], 3
[1, 2, 3], 5
[1, 1], 2
[1], 3
'''

# Complexity discussion

In the end some interviewers might ask, but it's always good for the candidate to proactively discuss the complexity of the solution. And again, do put your answer as artifacts for better communication and the recording purpose.

def two_sum(nums: List[Int], target: Int) -> List[Int]:
  d = {}
  for idx, n in enumerate(nums):
    if target - n in d:
      return [d[target - n], idx]
    d[n] = idx  # d: {1: 0}

'''
unit test cases:
[], 0
[1], 0
[1, 2], 3
[1, 2, 3], 5
[1, 1], 2
[1], 3

Time Complexity: o(N)
Space Complexity: o(N)
'''

# Conclusion

A successful interview is a result of good collaboration between the candidate and the interviewer. This blog discussed a few key steps and skills to enhance the effectiveness of a coding interview. In short, the candidate should be proactively demonstrating wanted attributes, such as expertise in data structure and algorithms, strive for ambiguity, proficiency in coding and unit testing.

# FAQ

# What if I have done this problem before?

Interviewer doesn't care if you have seen it before, unless the same problem has been asked in previous rounds of interview. Just jump directly to the optimal solution that you know. Do you try to optimize it little by little by proposing a brutal force solution at the beginning. Remember, time is money, you never know how many follow up questions are waiting for you.

# Why does the interviewer keep giving me hints / pushing me?

There are multiple reasons:

  • you have spent too much time thinking about a solution (> 20 min). The interviewer wants to see some of your implementation ability.
  • you are thinking on the wrong track and the interviewer tries to move you back to the right path.

# What if I cannot meet the speed requirement?

while (get_my_coding_speed() < TWO_LINES_PER_MIN) {
  practice();
}