The Wretched Google Interview Experience

I would like to describe my experience interviewing with Google, and specifically outline why I thought the experience was poor by way of telling my story. As you shall see, this will be especially difficult to convey because you, the reader, will likely be convinced my poor experience is likely only a result of being sour about not being accepted rather than an a posteriori analysis of the events that occurred. There are two conclusions I would like to make: First, Google is extremely bad at communication and human-to-human relationships in general (this is largely known by their customer service, or lack thereof), and second, that Google’s interview process is flawed.

Since I don’t want this to come off as a sob story, I will try to make it somewhat interesting by talking about the questions I got and keeping it in the style of a story rather than a complaint.

Initial Contact

A Google recruiter contacted me almost a year ago. I was working for a company in Colorado at this point, but I was in a bit of dismay concerning some financial mishaps that occurred, and I was interested in seeing what other opportunities there were. So I responded to the recruiter saying that I was interested. At this point, Facebook had also coincidentally contacted me and were interested as well. Both Facebook and Google promptly set up an interview, and I was sure to—at their request—let both of them know that I was interviewing for one another.

A week goes by, Facebook had already set up a phone interview, but Google was sort of tripping over itself. They said they would set up an interview within a couple of weeks, but nothing happened. I email them a few times, and I get no response.

A few weeks more go by, I’ve done phone interviews with Facebook and flown out to their offices to interview, and I’m extended an offer. Now I’m in a dilemma. Google says they are interested, but Facebook has given me an offer. I email Google one last time, and they never respond.

I accepted the Facebook offer, though somewhat reluctantly, because I felt I was closing out on another opportunity.

The Move

I decided to drive from Minnesota to California—a few days’ trek—after about a month since I accepted. (I wanted some time to pack things, get everything situated, change banks, find a place to live, etc.) After the month passes by, and I am on the road, driving through the Rocky Mountains, I get a call from a California phone number. I answer it, and it is another Google person. They tell me they are interested in interviewing. I told them that is what they said two months ago, and said that they would set up dates and times, but never did. The guy I was speaking to sounded somewhat sorry, but explained it must have just been an error in the system. I told the person that I was currently driving, and also that I had a new job starting in a couple weeks, but would still be interested in talking with him. He said he would call again later to discuss things.

The person did call again, and now I was in a more comfortable position. In a hotel room in Reno and not at a wheel in the mountains. The person asked what I was interested in, asked me about languages I’ve used, asked me if I’d be willing to work at Google despite having accepted a job, etc. I showed interest, and did want to move forward, which he acknowledged, and he said he’d email me the next steps.

I finally have moved into my apartment in California and started work. Many months go by, and was even interviewed and extended a better offer by another company, and Google never sent me the email.

Google’s Re-ignition

My interactions with Google started in about October of 2012, and Google called me in May of 2013, a third recruiter who saw me via LinkedIn, oblivious of my past interactions. Again, I got the “we are interested in interviewing.” This time, the recruiter did follow through and continue communication. However, the communication was not very pleasant. It was very canned and calculated. The recruiter asked me a questions like “Which language are you most comfortable in?” to which I answer that I am comfortable in many languages, and they respond “Well is it Python, C++, or JavaScript?” I tell them I have programmed professionally in all three of them and they just pigeonhole me into the Python category.

At around this time that Google contacted me, I had an offer from another company already. I told Google this, and they said they were happy to expedite things. They asked me if I knew anyone at Google, and in fact, I did. I knew four people. I was told that one of them gave me a shining recommendation, another described our work in the Lisp world and recommended me, another (very senior) who doesn’t know me as well nonetheless recommended me, and lastly someone at the director level did say I should be interviewed and also passed around my resume internally.

Finally, Google set up an on-site interview.

The Google Interview

Despite Google’s terrible track record so far for being organized and getting things done, I was still excited. I was so excited, I unfortunately could not sleep the night prior.

I drive to Google’s campus and wait about 30 minutes. The person I was supposed to meet went on a trip and did not tell me except via an automatic email that I received after emailing him asking “Where are you?” The recruiter comes along as backup and finds me, and takes me to my first interview. She asks me if I am ready, if I have used Google products before, and ensures that I will do just fine on the interviews as long as I am confident.

Interview #1: Maps and Sets

The first interviewer came and was 15 minutes late, but did get started right away. He asked me the following question

Create a data structure that has fast insertion, removal, membership testing, and random selection.

I poke around for a little bit and end up writing a chart of three or four elementary data structures, outlining the time complexities of each operation, but I suspected there was something better, which was confirmed by the interviewer’s push to see if I could develop something better. So next I try to mix the best attributes of one data structure with another. After some thinking, I finally got the details hammered out and mixed a hash table and a vector to produce something that has amortized constant everything. I felt victorious, especially since it is something I had to discover on the fly. For those interested, the code is here.

Interview #2: Servers and Data

The next interviewer came in, and he totally crushed me. I’m not even sure if I remember the question correctly.

If you have $n$ servers that take requests, and server $S_i$ can take a request every $t_i$ seconds, and you need to distribute requests to them as efficiently as possible, how do you do it?

I fumbled around a lot, trying to create an efficient loop, modding a timer and switching to the machine that needed the request. Then he asked how I’d add more machines at runtime, and I turned this loop with fixed time points into a data structure that associated $t_i$ to $S_i$. The interviewer thought this was completely unsatisfactory, and said “I wanted you to use a priority queue. We will just move to another question.” I felt pretty bad about this, but he asked another question.

If you have $n$ machines with a 10 GB string of characters on each, how do you find the most common character?

I got this one I thought. Just ask for a distribution of each character from each machine, send the tables to a master machine which added them up and found the character with the highest frequency. Then he asked questions like “If we make the network faster, does it make sense to send over all the data to one machine?” I respond “no”, and explain that it would actually degrade performance. Finally, toward the end, he asked

Now suppose you are in the middle of Africa, each machine is on an Edge network, and each packet between the machines costs $1.00. Write a solution that minimizes the cost.

There was only 5 or 10 so minutes left, but I thought that maybe I could incrementally determine the maximum. I started off by saying that each machine calculates a frequency table, but instead of sending the whole table, the master machine asks for the most common. I start describing very roughly the algorithm for doing this, but I don’t think I was getting the details and corner cases right. Time was very pressured, and the interviewer expressed dissatisfaction with what I’ve done. “Time’s up. Maybe you can ask your friend there what the answer is.” My friend was one of the people who recommended me and took me to lunch. He didn’t know the answer off the top of his head either.

I felt a bit unhappy with my performance, but thought that I got far enough that I must have did at least okay. I ate lunch with two of the people I know at Google, and one of them looked at my “docket” and exclaimed “this question is illegal.” He didn’t tell me which one but he wrote something down and gave it back to me. We finished lunch talking about language runtimes, Lisp, and Go.

Interview #3: Trees

This was probably the most straightforward interview. It started off with a discussion about languages. What’s good about C? What’s bad about it? What languages solve those problems? What languages introduce new ones? I mostly discussed type safety and memory safety, two things that I deal with most often in industrial code.

Then he moved for a technical question. I’m not sure if I remember the question accurately, though.

Given a list of pairs $(a,b)$ where $a$ is the number of a node and $b$ is its parent, construct a tree and return the root.

There may have been a third value $c$, but I fail to remember what it was if it even was.

I blazed through this. I wrote the code down to do so correctly and quickly the first time, and the interviewer actually said “I probably should not have asked a Lisp programmer about trees.” We spent the rest of the time (there was a lot of it) talking about Google and his position. I was particularly keen to figure out if he and his peers were solving tough problems or if most of the work was just tedium. I at least got an indication that he enjoyed what he did, but my question wasn’t really answered. Interview ended, and I felt good again.

Interview #4: Intervals and Regexen

I get to my next interview, performed by a very nice man with a quiet, Russian accent. He asked me the following question, though he asked it more cryptically than I write:

If you have a set of $n$ disjoint, sorted intervals $I = \bigcup_{k=1}^n [a_k, b_k]$, and you have an interval $I’ = [x,y]$, compute $I\cup I’$.

I’d worked with interval arithmetic before, and so I was in somewhat familiar territory. I quickly noted all of the possible cases, and proceeded to implement a solution that was actually more general than what the interviewer asked. I instead wrote a solution for the problem of computing $I$ efficiently given $I_1,\ldots,I_{n+1}$. It is a very easy generalization, and the interviewer saw that I think. Simplifying the union took no extra space and only took linear time, which was a sharp lower bound because we have to examine each possibly-overlapping interval at least once. The code for this is here.

He then proceeded to ask me questions about regular expressions, then asked me to write the regular expression for a variety of things.

Write a regular expression for floating point numbers.

I went through it, and even talked about what the DFA would look like, and describe why it would be very efficient to match.

I was even happier. Maybe lunch had helped! I thought this interview was a roaring success. We even had plenty of time to talk about Google and other things.

Interview #5: Dynamic Programming

The last interview was mostly okay.

Given a set of Lego bricks of height 1, 2, 3, and 4, each colored differently, write a program to compute the number of ways of constructing a tower of height $n\ge 1$.

This wasn’t a foreign question. Very quickly, I wrote down the typical exponential solution; just recursively count. It looks almost exactly like Fibonacci, but with four branches instead of two. I said it could be made a lot better, and computed in linear time. Here, I choked up a bit. I’ve done this a million times before. I started writing the iterative solution in Scheme, but I wasn’t getting the base cases quite right. I had to write out a few of the iterations, and after all that, I finally wrote it down, relieved. It felt almost scary, to forget something so trivial. The interviewer asked me if I could think of another way, and I couldn’t. Then he wrote down a 4-by-4 square matrix, and I basically completed his sentence: “Oh yes, of course, a nearly right triangular matrix that you project onto the first dimension by right-multiplying by a unit vector after doing binary exponentiation to $n$, just like Fibonacci.” I wrote down quickly using mathematical notation what the binary exponentiation looks like and what the projection looks like. He agreed, and we sat down and chatted some.

[Edit 1/10/2014] Many have asked how this works. Recall that the difference equation for Fibonacci numbers $F_k$ is \[F_{k+2} = F_{k+1} + F_k,\] along with the typical initial conditions $F_0 = 0$ and $F_1 = 1$.

This can be succinctly written as a matrix equation \[

\left(\begin{array}{c}

F_{k+2}\\

F_{k+1}

\end{array}\right)

=

\left(\begin{array}{cc}

1 & 1\\

1 & 0

\end{array}\right)

\left(\begin{array}{c}

F_{k+1}\\

F_{k}

\end{array}\right).

\] You can verify this by manually multiplying it out. By induction, this equation is \[

\left(\begin{array}{c}

F_{n+1}\\

F_{n}

\end{array}\right)

=

\left(\begin{array}{cc}

1 & 1\\

1 & 0

\end{array}\right)^n

\left(\begin{array}{c}

F_{1}\\

F_{0}

\end{array}\right).

\] The key here is that matrix exponentiation can be computed in $O(\log n)$ time by way of binary exponentiation. That is, to compute $M^n$ if $n$ is even, simply compute $M^{n/2}$ and square that result. If $n$ is odd, then compute $MM^{n-1}$.

Now we can generalize this to the Lego brick problem. Let the number of ways to arrange a tower of $n$ bricks be $L_n$. Then we have the difference equation \[L_{k+4} = L_{k+3} + L_{k+2} + L_{k+1} + L_{k},\] along with the initial conditions $L_0=1$, $L_1=2$, $L_2=4$, and $L_3=8$. (We will soon see that we can “simplify” the initial conditions, so as to remove the need to actually manually count them.) Similarly, it has the matrix relation \[\left(\begin{array}{c}

L_{k+4}\\

L_{k+3}\\

L_{k+2}\\

L_{k+1}

\end{array}\right)

=

\left(\begin{array}{cccc}

1 & 1 & 1 & 1\\

1 & 0 & 0 & 0\\

0 & 1 & 0 & 0\\

0 & 0 & 1 & 0

\end{array}\right)

\left(\begin{array}{c}

L_{k+3}\\

L_{k+2}\\

L_{k+1}\\

L_{k}

\end{array}\right).\] This can also be verified by expanding out. The intuition behind getting such a matrix is that column $c$ corresponds to $L_c$ in the input, and each value in the row is added up. So for a Fibonacci-like problem of size $N$, the first row—a row of $N$ 1′s—represents the sum of the last $N$ function values or “states” of the solution of the difference equation. And then each row indexed $m$ after the first must simply refer to the $(N-m)$th state, which that leads to an $(N-1)\times(N-1)$ identity matrix, padded with a column of 0′s on the right. So this technique lets us solve the difference equation \[ Q_{k+N} = \sum_{i=0}^{N-1} Q_{k+i} \] efficiently. (Exercise to the reader: This technique actually will let us solve a slightly more general difference equation of this form. What difference equation does it solve and what is the technique?)

Getting back on track to the Lego problem, the recursive matrix equation leads to the closed form matrix equation \[\left(\begin{array}{c}

L_{n+4}\\

L_{n+3}\\

L_{n+2}\\

L_{n+1}

\end{array}\right)

=

\left(\begin{array}{cccc}

1 & 1 & 1 & 1\\

1 & 0 & 0 & 0\\

0 & 1 & 0 & 0\\

0 & 0 & 1 & 0

\end{array}\right)^n

\left(\begin{array}{c}

L_{3}\\

L_{2}\\

L_{1}\\

L_{0}

\end{array}\right).\] If we adjust the indexes, and allow $L_{k<0} = 0$ (which is intuitively correct, we can make 0 towers with fewer than 1 block), then we can write a bit more elegantly \[\left(\begin{array}{c}

L_{n}\\

L_{n-1}\\

L_{n-2}\\

L_{n-3}

\end{array}\right)

=

\left(\begin{array}{cccc}

1 & 1 & 1 & 1\\

1 & 0 & 0 & 0\\

0 & 1 & 0 & 0\\

0 & 0 & 1 & 0

\end{array}\right)^n

\left(\begin{array}{c}

1\\

0\\

0\\

0

\end{array}\right).\] And indeed, this column vector multiplication is a projection of the matrix exponentiation (computed by way of binary exponentiation) onto the first dimension, which reduces the problem to $O(\log n)$ memory (stack space) and $O(\log n)$ time. We can do $O(1)$ space—equivalent to the dynamic programming approach—by doing the binary exponentiation bottom-up. (We can do this by looking at the binary representation of $n$.)

The Aftermath

I actually felt pretty good about my performance. I heard rumors that it’s okay to have a dud, and I thought I was in an especially favorable position since I had four people recommending me at various degrees, and since I nailed most of it.

I was called the next day by one of the recruiter managers, who was aware that I had a job offer elsewhere at this time, and left a message. “4 of the 5 interviewers have given me feedback, and it’s looking really good. I’ll let you know next week on Tuesday.” Monday was Memorial Day. I felt like I had it in the basket. A definite 4/5 and four employees on my side.

Tuesday rolls around, I eagerly await the phone call, and no one calls. Nor Wednesday or Thursday. It’s Friday again. Nothing. I shoot off an email:

It’s been a week since I heard anything from your end and was wondering if there’s any update before the weekend. (The last update I got was a voicemail message from you last Friday.)

About two weeks roll by, and I had no choice but to accept the job offer I was given weeks prior. A few days after I accept the other offer, Google does call me and said something along the following:

We decided we do not want to continue. You were a strong candidate but we felt you could use more experience. You can try again in 18 months. Sorry, I can’t give you any feedback otherwise.

This left me baffled. More experience in what? My resume needed more years, or I needed more algorithmic chops? I didn’t pressure him nor did I argue with him, but it suffices to say I was extremely surprised.

Google Rings Again and Again

A month or so later, a Google recruiter contacts me, and says “we are interested in interviewing.” What? Okay. I tell them, in full disclosure, that I just interviewed with them. They quickly get back to me and say

Oops! Sorry I didn’t see you in our database already. If you have any friends that want to interview, please let me know.

They also invited me to be a connection on LinkedIn, which I did not accept.

A few months go by, and I am on vacation in Boston, just hanging out with friends. I get a call. It’s Google. “We are interested in having you interview.”

I thought it was another mistake, but they acknowledge that I interviewed before, and they said that the 18-month rule is still in effect, but they were considering me for a Software Engineer in Test (SET) position instead.

There were two scheduled phone calls with the recruiter, and we discussed the position and how to move forward, and he sets up a phone call with an SET. The phone call with the SET was phenomenal I thought. An extremely nice guy, explained what he did very well. We chatted about my position, and he said I would probably be way more fit for a Software Engineer (SWE) position instead. I told him my past interview experience and he said something like

If I were Google, I’d cut the crap and just hire you.

That was very encouraging and somewhat flattering. Our phone call ended and he gave me his contact details and all.

I talked to the recruiter again who said that he would pass around my resume and see if any managers were interested, and I would do a half-day interview again. After he said that, a few hours pass and he emails me back saying “the managers would like to do a phone screen.”

What?

They have tons of data about me already, and they want to screen me? I can’t say no, so I say okay, and they set up a phone screen for the week after.

The Phone Screen

I get a call for the phone screen, and was asked to direct my browser to a Google Docs document. The interviewer dove right in.

Given a timer time() with nanosecond accuracy and given the interface

interface RealTimeCounter: void increment() int getCountInLastSecond() int getCountInLastMinute() int getCountInLastHour() int getCountInLastDay() implement the interface. The getCountInLastX functions should return the number of times increment was called in the last X .

To be clear, “in last $\Delta t$” means “the number of times increment was called between the current time $t_{\mathrm{cur}}$ and the time $t_{\mathrm{cur}} – \Delta t$, where $t_{\mathrm{cur}}$ is monotonically increasing. This was determined by the interviewer implicitly agreeing with my initial solution. [Edit 8/20/2013]

I froze up. How do I implement this? I just started coding.

I whip something up along the following lines: keep a history of timestamps and bisect it to find the least time greater than or equal to current_time - X . I knew there were issues with this. Theoretically, memory grows linearly with increment and is practically unbounded. (Theoretically, it is bounded because the timer is quantized, but practically, you can construct a case where memory fills up.)

I also discussed a way to prune the timestamps quickly, and it can be done on every query or every increment.

I spent the rest of the time trying to think of a way to bound the memory. The interviewer did not provide any hints or help, nor did he give any indication about what the actual issue with the code was. (In other words, I identified the issue with unbounded memory.) They simply said “would you like to spend the last 15 minutes cleaning this solution up or figuring out a better one?” I said I’d spend 5 more minutes thinking, and I’d make my decision then.

I couldn’t think of a better way, but did discuss some rough ideas. Could we bucket the times somehow? How do we deal with the edges of the buckets? I talked about a way to map time intervals to buckets, but failed to incorporate it into my solution. After 5 minutes was up, I stayed with my word and just cleaned up what I had.

The interview ended and I was mortified, I felt like I failed. Although I did write a full, working solution that had efficient time complexity, and theoretically efficient memory complexity, I knew it wasn’t practically sufficient. But something is better than nothing, yes?

I was told that I would be contacted within a day or two.

Post-Screen

I went online and asked two Google employees this question, two Amazon employees, an ARM employee, a CS PhD student, and a few other very smart people, but none of them came back to me with a solution that bounds the memory. One of the Google employees talked with one of their Google friends about it, and the friend said something like “It’s the interview question that people know because they look up the answer. And everyone always looks up the answer.” He proceeded to give me a hint over email about modding the timestamps, but I still fail to understand how it helps with edge cases (where the bucket size is greater than the resolution of the timer).

I hadn’t thought about it much, and a few of the people I talked to said they thought about it and still couldn’t figure it out.

A few days pass, and Google hadn’t contacted me. A week passes, and I email. No response. I call. No response. It has been a month minus two days, and Google still has not reached out to me.

My Google friend emails me telling me that he just gave me a recommendation to a Computer Science PhD position and said that it went well. He also added to the email that he checked my file at Google and saw that I was not accepted. But to this day, that has never been officially said.

Afterthoughts

Google has simply shown, in my opinion, an extreme lack of respect for the interviewee. Massively delayed or non-existent communications, sloppy bookkeeping, canned responses, pandering for applicants, etc. My interviews only consisted of a barrage of highly technical questions. Not once was my resume brought up. Not once was I asked about me in an interview.

Aside from being terrible at communication, Google implicitly rejected, without appeal, someone with offers for a PhD and someone who owns two checks from Knuth. But of course, credentials are not sufficient. My repositories, that contain code ranging from complicated group theoretic computations to implementations of set covering algorithms, meant nothing to them, even though I believe they subsume all of the gymnastics they put their interviewees through. It is a shame to see that current Google employees may also not have a job there, were they given the same set of interviewers as I had under the same circumstances. (And don’t get me wrong, they are extremely bright people and should be working at a top-tier company.)

Overall, I am quite appalled with Google’s interactions with me over the past year, and if there is this much contempt for interviewees like me, I wonder if they should be held in the same position.

More on interviewing in Silicon Valley can be found in this post.