Adventures in Interviewing: Bungie Part 2st

Editors note: To prevent painting an unsavory picture of the Bungie interview process, I edited part 1. I should have made it clear that it was my own neurosis at play, and not Bungie trying to be malicious. Though it may have come across that way, it was not my intent. If you hadn’t seen the edit, I’ll summarize: I received the test a few days later due to a glitch in the system.

I received the test in a word document. While gearing up for the test, I thought about all the different ways I could try for “extra credit.” One thing that sets me apart from other developers is my strength in a number of languages: C++, C#, Perl and Python are all languages that I can effective tackle any problem in. I thought that perhaps answering the test in all four languages might show off my skillset. After all, the position I was applying for was actually a C#/.Net Developer so why not do the test in both languages? Great, that will show them how eager I am to work for Bungie!

The test consisted of three questions:

  1. Write a function that is constrained for time and space that given a char* sentence, returns the sentence with the words in reverse order. Example: “How now brown cow” becomes “cow brown now How.” The function can modify the original char* array
  2. Write a function that is contrained for time and space that given a a linked-list with a random pointer to an arbitrary element and a pointer to the next element, returns a new copy of the linked-list with no dependancies on the orignal list. The function can modify the original linked list, but must restore the linked-list to it’s original state prior to completion
  3. Write a generalized Boggle program, that given a NxN board of characters, and a dictionary, returns all the possible words.

Use proper engineering principles, but understand that developer time is important. Because of the skill-set of the team reviewing your code, use only C/C++, and language and library references are okay, but no external help for the “meat” of the algorithms.

Well fuck. There goes my extra credit attempt. What else could I come up with? I could try to write a graphical implementation of Boggle, but under the time contraints, it would be a close call. I was given a week to do the project, but the HR lady said because of my “free time” I should probably finish sooner.

I let the problems sit on the backburner while I went about finishing up what I was doing.

Then it was time to tackle the problems. I had an idea of how to tackle the string and boggle problem, but not the linked list one, so I started with the string.

I came up with a simple algorithm:

  1. Create a temporary buffer the size of the sentence
  2. Keeping track of the end of a word, and the start of a word, starting from the end of the sentence, move the start-word-tracker backwards, until you find a space.
  3. Copy the letters between start-word-tracker+1 and end-word-tracker to the temp buffer.
  4. Move the end-word-tracker to where the start-word-tracker-1 is, checking to make sure you don’t move past the end of the sentence, and repeat 2-4, until you reach the beggining of the sentence
  5. Copy the temp buffer to the original, and return

Great, this solves the problem and only requires one-pass through the sentence plus the copies to the buffer. However it requires allocating a temporary buffer, doubling the size of memory. So time complexity O(n) and space complexity O(n). Since there is no way to iterate all the words in the sentence, time complexity O(n) is probably the best we will achieve. But we should be able to beat the space requirements. The problem description itself gave the hint: you’re free to modify the original string. So I figured out that we should be able to copy the characters in place to the original string.

Not trivial.

The algorithm I came up with for this was quite a bit more complex. It essentially swaps the last word with the first word, moving in one word space towards the middle per swap. If one word is larger than the other, we store it in a temporary variable. The problem with this, was the extra values needed to keep track of where we were in the sentence. Analysis on this approach was space complexity O(1) on the best case (we never have to reallocate a temp variable), O(m) average case and worst case. Not great, but a little better than the faster, quicker to code solution. Since this solution was a bit more kludgy I knew there had to be a better way to solve this. Unfortunately I was unable to figure out the “trick.” Turns out if you first reverse all the letters in a sentence, then reverse the letters in a word, you’ll end up with the desired answer:

“How now brown cow” => “woc nworb won woH” => “cow brown now How”

This can be done inplace (space complexity O(1)) and in linear time ( O(n) ). This is the best solution. Too bad I didn’t get it. But, what if I show the progression I made from the “obvious” answer to an answer that is slightly better. Perhaps partial credit is in order? Maybe that’s how I can show how good of a developer I am! I decided to attempt to answer the question twice: one for the obvious answer, and one for the better more optimal answer.

For the second problem, the obvious solution was to use an associative container (std::map) to store a quick lookup between the original list node, and the new list node. The algorithm looks like this:

For each list node:

  1. create a new list node
  2. store the new list node into a map, using the original list node as the key

Once complete, for each list node in the original and new list:

  1. Set new_list_node->random to point to map[org_list_node->random]

This works! Time complexity O(n) because we make two traversals of the list. Space complexity O(n) because we make two copies of each node used in the map. Is there a way to copy the linked-list without using a map? Of course, and the question had a hint: you can temporarily modify the original list, so long as you restore it upon program completion.

So we know we can modify the original list, but have to restore it. So that gives us essentially 4 pointers to work with: the original lists next and random pointer, and the new lists next and random pointers. The easiest way to see the algorithm is to visualize it.

First pass: create the new list, and associate it’s next pointer correctly.

Second pass: for each element in both lists, assign new->next to original->next, and then orginal->next to new.

Third pass: for each element in both lists, assign new->random to original->random->next, iff original->random is not null.

Fourth pass: for each element in both lists, assign original->next to new->next, then new->next to orginal->next->next, iff original->next is not null.

So visually you should be able to tell what is going on. Analysis of this algorithm: Time complexity O(n), Space complexity O(1). It may be possible to improve by only doing a single pass through the linked list, but that still is O(n) [admitedly if N is large, and you end up paging, a single pass is most definitely preferred to 4...]was pretty happy with this answer.

Part 3 will have the solution to the final problem, and the conclusion to this wacky adventure! Stay tuned.

Adventures in Interviewing: Bungie Part1

A while back I had one of the greatest chances to fulfill one of my life dreams: work for a bad ass game studio. Bungie Game Studios, or Bungie, fits that mark. They’re the studio responsible for the multigigallion dollar Halo franchise, developing Halo Combat Evolved, Halo 2, Halo 3, Halo ODST, and now Halo Reach. Prior to that, they were most famous for the Marathon series of games, a FPS on the Mac.

Megs has a friend whose husband works for Bungie. We’ve hung out a few times, going to comedy shows, dinners, and such. The couple are pretty cool with the Bungie hookups, even going so far as to getting us into the Bungie VIP party during the ODST launch. So through him I got my resume in front of someone who was actively looking to fill a Server Database role. A week passed, and no word, so I dutifully followed up with a more impassioned email directly to the lead Server developer. The next morning I was contacted by HR.

Hot dog.

I setup a time for a phone interview with the head of HR.

The phone interview was pretty basic; mostly going through my resume, asking me in detail about every position, finally following up with the next steps for the recruiting process: A take home programmer test, a phone interview with a dev lead, a phone interview with a senior engineer, followed by an in person interview. Serious stuff.

She mentioned that the company takes the programmer test very seriously, meeting as a team to go over the results, and that despite it being “easy for someone like me” the test has a high failure rate. Maybe I should have told her that I was the first person to score negative on the SATs. The test was in C/C++, though the position was a .NET C# developer. The logic behind it was that if you know C/C++ then transition to C# your somehow better than learning C# first then transitioning to C/C++. Add to this, that depending on project load level, developers are pulled from various projects to help out, so being highly skilled with multiple languages is essential. She asked if I was still interested in continuing, and of course I said yes. It concluded with her telling me that I would receive the test later that day, and that they typically expect it back in a week. I thanked her for her time. After I hung up, I gathered the materials I would need in preparation.

Due to an emailing snafu, I didn’t end up receiving the test till the following Wednesday. Sometimes I can get a bit neurotic, and due to my strong desire to work at Bungie, I started to read way too much into the slight delay. However, I did my due diligence and followed up with HR and received the test and was off to the races!

Stay tuned for Part 2!

Today’s Interview

About 8 months ago, I left my full time job to work independently. I went picking mushrooms in the mountains, came out and decided that it was time for me to change. I sold myself the idea based on the numbers, and the increased free time to pursue independent projects.

Things have gone really well for me. I enjoy the freedom of setting my own schedule, choosing which projects to devote my time, and having nearly unlimited vacation time (a huge plus when you are a travel junkie). The obvious downsides, which are oft repeated elsewhere, the lack of security, and stability.

The contract I had been working has now expired, and I’m in the process of securing some new ones–while also looking for my dream job. Today I met with the VP Engineering for a startup, whom I was introduced to, through a previous client of mine.

I assumed it would be an informal meeting, just to talk expectations, but it turned out to be a full-on software position interview! Luckily I recently interviewed for a dream job and had shaken off the ring rust.

He started off by explaining a bit about what the work entailed, then asked for some background information. I explain that I really enjoyed solving hard problems, giving him the example of “Fixing traffic in Seattle” as a type of problem I would love to tackle. I was asked to do some white board coding–admittedly one of my weakest aspects for me during software interviews.

The first question: Given a byte compression algorithm that strips the leading bit (always 0) and puts bits together, write a decompression algorithm.

Example: with two bytes a = 01001111, b=01001000 comes across as:

10011111 001000xx

My approach to solving this problem first recognized that you could write a custom class that used a vector of booleans. In C++ this is optimized for space, and mimics a bit-vector class. After a few minutes, I talked myself out of this solution–mainly vector is great for constant access, but isn’t great for deletes, which would occur everytime you read a new 8-bits from the compressed stream.

Next I thought what structure would be better–probably a FIFO queue, and explained why. For the sake of time, I decided to go to the more complicated approach: using bit shift operators.

I talked through what we’d need to do: store the last byte read (as it would have the first bits for the next byte), keep a count of the remaining bits. We’d initialize the return byte to 0, then shift in the bits from the last byte read, then from the new byte read, update the counts, etc. Not elegant, but I think it answers the question.

Next was a thought question: How would you go about finding out the number of dentists in Seattle?

My first guess was to contact the ADA. Since you need to be licensed to practice dentistry, the ADA should have a list of licensed dentists (you could just contact the licensing board for King County/WA state also), and you could filter that out by area. For arguments sake, the ADA only has a list for Washington, how to proceed? Well next I suggest brute force. You could call every number in the seattle phonebook and ask if they’re a dentist. Obviously not even close to being a workable solution. Then I said, find the number of dentists in the yellow pages, as a start.

I was then asked a variation of the question: how to find the number of plumbers in seattle? Obviously the phonebook answer would hold here, but I got a sense that it wasn’t what he was looking for. So I gave what I thought was a silly answer: “Maybe it’s a function of the number of toilets. So figure out how many toilets per plumber.” Turns out that was the answer he was looking for, and that you could probably estimate the number of dentists as a function of teeth.

The final question was related to the actual position. He described the problem domain, and asked how I might improve the system. I talked through a few ideas, and one seemed well enough.

He explained the next steps in the process, said he’d be in touch, and thanked me
for my time.

Overall, I thought it went well. From his feedback it sounded like I qualified, at least technically, for the position, so we’ll see.

I do think It’s a bit silly that though I’m aware that my whiteboard coding skills are weak, I haven’t invested much time to strengthen them. I’ll work on that.

By the way, what have you done that’s so great?

I’ve decided to change the focus of this blog. No more random, negative, cynical posts about nothing, and instead posts about programming, software careers, and perhaps the occasional travel or photography post.

The title, isn’t an attack on others. More of a reflection, brought on when I read Steve Job’s response to a random emailer complaining about Apple’s change in policy regarding 3rd party iOS App makers. It got me thinking. What have I done that’s so great?

Thus I’m hoping this blog might allow me to answer that question. I don’t have dreams of being the next Joel on Software, Jeff Atwood, or Jon Skeet, but I do want to use the web to put down my thoughts on my career on software, using it as a way to help potential companies with great problems find their way to me, a great problem solver.

My ultimate goal is to find a job, or create a company that has insanely hard problems to solve, and to set about solving them. I’m great at working hard for hard problems, and really bad about working hard for easy ones. Give me a challenge, and an unrealistic deadline, and I’ll give you a solution.