Google interview questions constructed: the knight’s dialerhttps://medium.com/@alexgolec…
As an engineer and interviewer of Google, today is the second time that I have published an article to share the interview suggestions of a technology company.Here is a statement: This article only represents my personal observations, opinions and suggestions. Don’t take it as an official suggestion or statement from Google or alphabet。
The following question is the first one in my interview career; it is also the first one that has been leaked and banned. I like this question because it has the following advantages:
- The question is easy to express and understand.
- There are multiple solutions to this problem. Each solution needs different degrees of algorithm and data structure knowledge. And a little bit of foresight is needed.
- Each solution can be implemented in a few lines of code, which is very suitable for time limited interviews.
If you are a student or a job seeker, I hope you can understand what interview questions are like. If you are also an interviewer, I would like to share my own style and ideas in the interview, how to better convey information and ask for opinions.
Note that I’m going to write in Python; I like Python because it’s easy to learn, simple, and has a huge standard library. Many of the interviewers I met also liked it. Despite our “unlimited language” policy, 90% of the interviewees I interviewed used python. And I use Python 3 because, please, it’s 2018.
Think of your phone’s dial page as a chessboard. Chess pieces can only walk in the shape of “L”, two steps horizontally and one step vertically; or two steps vertically and one step horizontally.
Now, suppose you can only dial like a chess piece in the shape of “L”. After each “L” dial, the starting position is also counted as a dial. Question: how many different numbers can you dial in N steps from a certain point?
Every interview, I will basically be divided into two parts: first, we find out the algorithm scheme, and then let the interviewer implement it in the code. I said, “let’s find the algorithm solution,” because I’m not a silent dictator in this process. Under such high pressure, 45 minutes is not enough to design and implement an algorithm.
I usually let the interviewers lead the discussion and let them have ideas. I’m right next to you, and I’ll let you know a little bit of “secrets” from time to time. The more capable the interviewers are, the less “secrets” I need to reveal; but so far, I haven’t met any interviewers who don’t need any tips from me.
I want to emphasize one point, which is very importantAs an interviewer, my job is not to sit there and watch people fail and screw up. I want to give you positive feedback, give you the opportunity to show what you are good at. To give them a hint is like saying: Nah, I’ll pave the way for you, but it’s just for you to show me that you can go further on the road behind.
What should you do after listening to the interviewer’s questions?Remember not to write code immediately, but try to break down the problem step by step on the blackboard. Decomposing problems can help you find rules, special cases and so on, and gradually form solutions in your brain. For example, if you start with the number 6, you can take two steps, and there will be the following combinations:
6–1–8 6–1–6 6–7–2 6–7–6 6–0–4 6–0–6
There are six combinations. You can try to draw on paper with a pencil, and believe me, sometimes when you start to solve problems, unexpected things will happen, which is more magical than when you stare in your head and think.
What about? Do you have a plan in mind?
Level 0: get to the next step
What surprised me most about using this question interview is that too many people are stuck in calculating how many possibilities there are when they jump out of a specific point, that is, neighbors. My advice is: when you’re not sure, write a place holder first, and then ask the interviewer if you can implement this part later.
The complexity of this problem is not in the calculation of neighbors; what I care about is how you calculate the total. All the time spent calculating neighbors is a waste.
I would accept “let’s assume that there is a function that gives me neighbors.”. Of course, I may also let you have time to achieve this step later. You just need to write like this, and then continue.
Moreover, if the complexity of a problem is not here, you can ask me if I can skip it first. Generally, I allow it. I don’t mind that the interviewer doesn’t know the complexity of the problem, especially when they haven’t fully understood the problem at first.
As for the neighbors function, because the number will never change, you can write a map directly and return the corresponding value.
Level 1: recursion
Smart you may have noticed that this problem can be solved by counting all the numbers that meet the conditions. Here you can use recursion to generate these values:
This method can, and is the most common method in the interview. But please note that we have generated so many numbers, but we don’t use them. After we count them, we don’t touch them any more. So I suggest that you try to think about whether there is a better plan in this situation.
The second order: the number does not count
How to calculate the number without producing these numbers? It can be done, but it takes a little tact. Note that the number of digits that can be dialed n times from a specific point is equal to the sum of the number of digits that can be dialed n-1 times from all its adjacent points. We can express it as a recursive relation
If you think so, it will be very intuitive. When you jump once: 6 has three neighbors (1, 7 and 0). When you jump 0, each number counts as one, so you can only dial three numbers at a time.
How did you come up with such a clever idea? In fact, if you learn recursion and study it on the blackboard, it will become obvious. In this way, you can continue to solve this problem. In fact, there are many ways to achieve this. The following is the most common one in the interview:
That’s it. You can calculate neighbors with this function. At this time, you can pinch your shoulders to rest, because you have brushed off a lot of people.
Next, I often ask this question: how fast is the algorithm theory of this scheme? In this implementation, count is called every time_ Sequences () will call count recursively_ Sequences () at least 2 times, because each number has at least 2 neighbors. This causes the runtime to grow exponentially.
It’s OK to jump one to 20 times, but we’re going to hit a wall when we get to a bigger number. 500 times may require the heat of the entire universe to complete the calculation.
Level 3: memory
So, can we do better? Using the above method, it is not possible. I like this problem because it can bring out people’s wisdom layer by layer and find more efficient methods. To find a better way, let’s see how this function is called to count_ Take sequences (6,4) as an example. Note the simplification here with C as the function name.
You may have noticed that C (6,2) runs three times, each time doing the same operation and returning the same value. The key point here is these repeated operations. Every time you use their values, there is no need to calculate them again.
How to solve this problem? Memory. Let’s make those same function calls and results instead of having them repeat. In this way, we can give the previous results directly later. The implementation method is as follows:
Level 4: dynamic design
If you look at the previous recursive relationship, you will find that the recursive memory scheme also has some limitations
Note that the result of jumping N times depends only on the result after the N-1 jump. At the same time, the cache contains all the results of each number of times. The reason why I say this is a small limitation is that it really does not cause a real problem. When the number of hops increases, the cache only grows linearly. But, after all, it’s not efficient enough.
What should I do? Let’s look at the solution and code again. Note that the code starts with the maximum number of times, and then recurses directly to the minimum number of times:
If you think of the entire function call graph as some kind of virtual tree, you’ll see that we’re implementing a depth first strategy. There’s nothing wrong with that, but it doesn’t take advantage of the shallow dependency property.
How to implement breadth first strategy?Here is an implementation method:
What’s better about this version than the previous recursive version? In fact, it’s not much better, but it’s not recursive, so it’s hard to crash even when dealing with large data. Second, it uses constant memory; finally, it still grows linearly, even processing 200000 hops in less than 20 seconds.
Here, it’s almost over. Design and implementation of a linear, output memory program, in the interview is a very good result. In my interview, if an interviewer writes dynamic programming design, I usually give him a very high evaluation: excellent!
When evaluating algorithms and data structures, I often say: the interviewer has a clear understanding of the problem, and considers the possibility of all aspects. When he points out the shortcomings, he can quickly improve and improve; finally, he realizes a good solution.
When evaluating code, my ideal statement isInterviewers translate ideas into code quickly and accurately; the code is well structured and easy to read. All special cases are summarized, and the code is carefully checked and tested to ensure that there are no bugs.
I know, this interview question seems a little scary, especially the whole explanation is very complicated. But the purpose of this article is totally different from that of the interview.Finally, a little interview related skills, as well as some good habits, to share with you：
- Be sure to do it manually, starting with the smallest problem.
- When your program is doing useless operations, be sure to pay attention to optimization. Reducing unnecessary computation can make your solution more concise, so you may find more efficient solutions.
- Learn about your recursive functions. In actual production, recursion is often prone to problems, but it is still a very powerful algorithm design and strategy. There is always room for optimization and improvement of recursive schemes.
- Always look for opportunities to remember. If your function is purposeful and calls the same value many times, try to store it.