Technical questions Flashcards

1
Q

List the steps of solving a technical question.

A
  1. Listen
  2. Example
  3. Brute force
  4. Optimize
  5. Walk through
  6. Implement
  7. Test
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Detail phase

(1) Listen

A

Pay very close attention to the problem description. Write the pertinent [1] information on the whiteboard.

You probably need it all for an optimal algorithm.

[1] Record any unique information. E.g. “given two sorted arrays” or “algorithm to be run repeatdely on a server”.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Detail phase

(2) Example

A

Draw an example on the whiteboard:
1. Specific: Use real numbers or strings (if applicable).
1. Big enough. [1]
1. Not a special case. [2]
1. Get the interviewer’s explicit confirmation.
1. Make the best example you can in the first go. [3]

If it later turns out your example isn’t quite right, fix it.

[1] It’s hard to find patterns if the example is too small, like a 3 node binary search tree.
[2] Be vey careful. It’s very easy to inadvertently draw a special case like a balanced tree. If there’s any way your example is a special case (even if you think it probably won’t be a big deal), you should fix it.
[3] Don’t move on with an obviously flawed example with the plan to fix it later as you understand the problem better.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Detail phase

(3) Brute force

A

Get a brute-force solution ASAP. Don’t worry about developing an efficient algorithm yet. State a naive algorithm and its runtime, then optimize from there.

Don’t code yet!

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

During the “Brute force” phase, should you write some code?

A

No.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

During the “Brute force” phase, should you state the big O?

runtime / space complexity

A

Yes.

This will help in the following optimization step.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

During the “Brute force” phase, should you test the code?

A

Not in detail [1]. But do quickly run through 1-2 approved examples.

[1] The algorithm will change during optimization.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Detail phase

(4) Optimize

A

Walk through your brute force solution:
1. Look for any unused info. [1]
1. Make a time vs. space tradeoff. [2]
1. Consider precomputation.
1. Consider best conceivable runtime (BCR).
1. Apply the 5 “Optimize and Solve” techniques.

[1] You usually need all the information in a problem.
[2] Hash tables are especially useful! Present the trade off. Let the interviewer pick a side.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Detail phase

(5) Walk through

A

Now that you have an optimal solution, walk through your approach in detail:
1. Get a feel for the structure.
2. Know what the variables are and when they change.
3. Have a clear idea of the implementation for each part. [1]
4. If pseudocode, keep it short and high level.

It’s faster to fix conceptual errors now than after implementation.

[1] If you don’t understand exactly what you’re about to write, you will struggle to code it. It will take you longer to finish the code, and you’re more likely to make major errors.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Detail phase

(6) Implement

A

Your goal is to write beautiful code:
1. Start in the top left corner.
2. Keep code lines straight and short.
3. Check the validity of all input and values returned by helpers. If time permits, explicitly, otherwise, add TODOs for validity checks and talk out how you would handle which kind of invalidity.
4. Implement from most to least abstract. [1]
5. Modularize your code from the beginning. [2]
6. Use expressive variable names.
7. If variable name too long, explain that you will use an abbreviation starting from the second usage, like “sc” for “startChild”.
6. Refactor to cleanup anything that isn’t beutiful - or at least add a TODO and explain what you would refactor.
7. If you get confused, walk through the example again.

You only have this little code to demonstrate that you’re a great DEV.

[1] Assume custom classes and less abstract functions already exist. Implement them later if time allows / interviewer asks for them.
[2] Separate class for each data structure. Separate function for each “one thing” in the sense of CC.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Detail phase

(7) Test

A

Test in this order:
1. Conceptual tests. Walk through your code like you would for a detailed code review.
2. Unusual or non-standard code, e.g. length - 2.
3. Hot spots, like arithmetics and null nodes.
4. Small test cases. [1]
5. Special cases.

And when you find bugs, fix them carefully.

[1] Don’t use the big 8-element array from the algorithm part. Use a 3-4 element array. It’s much faster than a big test case and just as effective.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

In the “(7) Test” phase, how big should be the test cases?

A

Rather small. Don’t use the big 8-element array from the algorithm part. Use a 3-4 element array. It’s much faster than a big test case and just as effective.

But not too small, so that it doesn’t become a special case.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

List the 5 “Optimize and Solve” techniques

A
  1. Look for BUD
  2. DIY (do it yourself)
  3. Simplify and generalize
  4. Base case and build
  5. Data structure brainstorm
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Define the “optimize and solve” technique

(1) Look for BUD

A
  1. Bottlenecks [1]
  2. Unnecessary work
  3. Duplicated work

Check for those during the “Optimize” phase.

[1] The parts of the algorithm which contribute most to the big O complexity.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

In BUD optimization, what are “bottlenecks”?

A

The parts of the algorithm which contribute most to the big O complexity. Common types:
1. Slow one-time work: Imagine an algorithm which does some work A once, and then some work B once. If A is O(n^2) while B is O(n), A is the bottleneck. There is no point in optimizing B as long as the runtime of A is bigger than the one of B.
2. Slow repeated work: Imagine some work A with O(n), done n times, resulting in a total runtime of O(n^2). Can A be reduced to O(log(n)) or O(1)? Maybe with some precomputation or caching?

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Define the “optimize and solve” technique

(2) DIY (do it yourself)

A
  1. Pick a nicely big example.
  2. Find the expected result manually.
  3. Pay attention to the brain’s intuitive optimizations.
  4. Backwards engineer the algorithm from what you just did intuitively.
17
Q

Define the “optimize and solve” technique

(3) Simplify and generalize

A
  1. Find a simplified version of the problem which seems easier to solve.
  2. Solve it.
  3. Adjust (usually: generalize) the simpler problem solution to account for the full complexity.

Example:
* Full problem: Given two strings, P and A, can the phrase P (sequence of words) be built from words in the article A?
* Dealing with words is harder than with characters.
* Solve “Can P be built from the characters in A?”
* Then adjust the solution to work with “words” instead of “characters” in A.

18
Q

Define the “optimize and solve” technique

(4) Base case and build

A
  1. Solve for n=1 by hand.
  2. Build the solution for n=2 based on the solution for n=1 by hand.
  3. Build the solution for n=3 based on the solution for n=2.
  4. Is there a pattern so that you can build a solution for n=x based on n=(x-1)?
  5. Express the pattern in an algorithm.

This usually results in a recursive algorithm.

Example:
* Find all permutations of a string like "abcdefg".
* Start with n=1, i.e. the permutations of "a": P("a") = {"a"}.
* Now n=2, i.e. P("ab") = {"ab", "ba"}.
* We can solve P("abc") by taking each of the results in P("ab") and sticking the new "c" at any position.
* Generalize that as a resursive algorithm, with base cases for n=0 and n=1.

19
Q

Define the “optimize and solve” technique

(5) Data Structure Brainstorm

A
  1. Go through data structures like Array, Linked List, Binary Search Tree, Heap, HashMap.
  2. For each, think if it could help somehow.
20
Q

Explain

Best Conceivable Runtime (BCR)

A

Without any particular algorithm in mind, what is the bare minimum number of operations?

The BCR is not necessarily achiavable by a real algorithm but no algorithm can do better than the BCR.

The BCR helps in various ways:

  1. When the algorithm at hand is worse than BCR, it’s a hint how much we may be able to optimize where.
  2. Any added work which is less or equal to BCR is “free”, i.e. it doesn’t impact the resulting runtime.
  3. When the algorithm at hand does have the same runtime as BCR, we know we’re done optimizing the runtime and can start looking at space complexity.

Example:

Compute the number of common elements between two arrays of sizes A and B.

The BCR is O(A+B) because we’d need to “touch” each element in each array at least once.

If we start with a brute force, comparing each element in A with each element in B, we get the initial runtime of O(A*B). BCR tells us that we may be able to do better.

BCR also hints at the area of improvement: if we want to achieve O(A+B), we need to touch each element in both arrays a constant number of times (rather than each element of B for each element of A).

The BCR of O(A+B) tells us that touching each element a constant number of times is “free”. The optimization tips suggest to consider precomputation and hash tables. Both is useful here: We could put each element of A into a hash table (O(A), i.e. “free”). Then, for each element of B, check if the table has such (O(B)).

In total, this results in O(A+B), which matches the BCR, i.e. we know that we cannot do better than that in terms of runtime complexity. Now, we should think about space complexity.

21
Q

List ways to improve the code’s maintainability.

A
  1. Use custom data structures generously.
  2. DRY via reused helpers.
  3. Modularize via helper functions.
  4. Add flexibility [1] if time allows.
  5. Add error checking for input and values returned by helpers.

[1] Flexibility: The algorithms ability to work without certain limitations in the interview question. E.g., when asked for a solution for a 3x3 field, implement a solution for an NxN field, or even NxM.