A Google Interviewing Story
paultyma.blogspot.com
paultyma.blogspot.com
I'd far rather see a developer cross 10 items off the to-do list instead of cross 1/2 of an item off a to-do list, and get lots of style points.
It's good to see that a candidate has creativity to come up with solutions like this. But I'd want to temper that by also seeing if they have the good judgement to know when to use such things (almost never).
Gah, so much fail in that answer, but the worst thing is that the guy proposed it as a better alternative, and the interviewee admired it!
Consider an original string 'bb', and a test string 'c'.
With powers of two, you'd have 2*2, and your test would be a division by 4, which would be successful by having no remainder, indicating that 'c' is a subset of 'bb'.
If A = 2^1, B = 2^2
AA, B would evaluate to true.
But you're right, the running times aren't any better, except that the constant factors of dealing purely in arithmetic might make it faster in real terms if dealing with a lot of this type of thing than creating hash maps. If response time matters for the application (high frequency trading, etc), it might make a difference.
Now it's true, that these are both linear time solutions simply with different factors and we might simply say who cares. The thing about the prime solution is that it's actually really dumb itself and I think that's what Guy really wanted you to tell him. He was pointing out that you could leverage the smallness of your data and hoping the interviewee would come up with an even better way to leverage this fact.
The first thing we should notice is that asymptotic bounds are misplaced here if you consider how such a function might actually be used. The strings are basically being used as sets that is AA might as well be A as far as our answer is concerned. So assuming people aren't giving us stupid data (and in an interview you could mention a way to make this assumption true). The strings shouldn't ever have duplicates and thus shouldn't ever be bigger than 26 characters (otherwise they contain all of the characters and the answer is independent). So if a solution has runtime n + m + c, that c actually starts to matter.
The thing about the primes solution is that multiplication and modulo operations are actually very expensive and all you want to keep track of is whether you've seen a character (1 bit of information) so you should really use a bitmap for this. And since it so happens that 26 < 32 these will fit very nicely in a single int. It's even a pretty nice implementation: https://gist.github.com/707639
[edit: link to code]
Shouldn't it be
seen ^= mask(haystack);
And a personal change would be to define all as:
int all = ~(~0 << ('z' - 'a' + 1));
EDIT: For some reasons, asterisk doesn't appear before haystack.
But, I'm sure, I would suck so much at this kind of interviews. If you are anything like me you'll understand what I mean, in topics where I work day by day I've pretty much the control of what the good solution can be in a few minutes, but for many things to find the best solution requires, at least for me, days of thinking, sleeping, possibly waking up with the solution in mind, to find it's wrong and you need to reiterate the process.
My design abilities are all there, in this days. I'm sure that in the five minutes race I would say many times something of super stupid. Now my question is, are the five-minutes performances really linked to the three days thinking about your problem solution?
Isn't it possible that at least a subset of guys that will get the few-days answer well, will instead provide a poor answer in little time, and sometimes the other way around?
If this can be somewhat true, there is a huge industry selecting runners for 100 meters, in order to run, most of the times, a maraton.
Multiplying n primes together creates an O(n) digit number. Multiplying an O(n) digit number by a constant is an O(n) operation. So essentially we're doing an O(n) operation n times, hence O(n^2).
The smartest representation that I can think of for the numbers would be to store the prime factor exponents in an array, which would essentially transform the algorithm into the array based version. For example 120 = 2^3x3x5 would be represented as {3,1,1,0,0,...}.
BTW, I would've used a bitvector. For lowercase letters only, you could fit it into a 32-bit value (add mixed-case and numbers and you can fit it into 64 bits), then it's just an OR to set a bit and an AND to read if a bit has been set, both fast machine-level operations.
Edit: Didn't see the footnote on the problem. A bitvector doesn't work if counts must be kept, but you can still do this pretty simply with the table solution.
I interviewed for a Program Management position in the Visual Studio group. My first interview was with the Design Manager for the VS product line. Her final question for me was about building an effective temperature control system for a new house. I launched into a 5 minute analysis of the advantages and disadvantages of a wide range of HVAC systems, obvious ramifications from open floor plans, and so on.
A month later, we sat down for lunch as co-employees for the first time, and I told her the whole story. She got a big laugh out of it. I guess she didn't realize that's what I'd spent the last few months working on.
Standard counter-intuitive example (from the game development domain) is how to check if an array of integers has a zero in it. The answer, when all things are considered, is to scan through an entire array making a simple arithmetic for each item and one comparison at the end rather than compare each element.
The same may happen with your example. Filling up 32-bit mask might be more expensive than to flip an element in a boolean array. That's not even considering that the array option allows for early termination of the second loop.
Multiplying together the first 26 primes requires that you can store a number up to 232862364358497360900063316880507363070. log2 of that number is about 127.5. So you need 128-bits of storage.
Essentially, the correct solution is to sort both lists, and then do a single pass through checking for unique items in one list. Once you have this solution, you can do some micro-optimizations: - note that the set of symbols is limited, so you can use a counting sort (or other non comparison based "sort") - note that the sorting function doesn't need to be an actual sorting algorithm, and may discard duplicates.
If you apply these two optimizations, you should end up with the bit-field approach (or maybe a slightly more memory hungry one that doesn't store stuff in individual bits... but algorithmically it doesn't bring anything new to the table).
For some reason, a minority of people are then thinking that a further optimization is to use a more inefficient data structure in the sorting algorithm for storing whether or not a letter has been seen. This has the effect of a more expensive read operation, write operation, more memory usage and provides no other benefits.
The hash table solution is O(n+m). 24 operations on the example. The array solution is O(n+m) and 24 operations. The same.
Your intuition tells you that the array is faster because subconsciously you're making assumptions about implementation details. What if you're in a language like PHP where arrays are implemented as hash tables? What if you're in C, but the hash table implementation uses a resizable array and happens to choose an initial size of 26?
Characters can repeat, so a boolean array doesn't work.
Plus, the story says I mumbled awhile that given the characters were limited to alphabetic (his original specification) that I could use an array instead of a hashtable for some constant time savings but that was about it.
In this case the question says find out if all the characters in the smaller string are in the larger string, so yes, I think you are right - the repeats don't matter here.
A Bloom filter is usually used where representation size is important, because it can be orders of magnitude smaller than a hashtable. It doesn't perform very quickly though, because of the hashing operations needed during insert.
A Bloom filter is great for P2P search applications for example. Then peers can pass Bloom filters around, and an initial search can happen locally. If it succeeds then the search can ask the remote host if the file actually exists. The frequency those remote requests will fail depends on the number of false positives the Bloom filter is configured to give (ie, a function of its size).
Consider the following string, where   is a non-breaking space:
Main string: "Counter example:  _à²"
Shorter string: "ಠ_ಠ"The array of bools, bitmap (remember 32-bit int!), hash map; all are the same basic deal, easy to understand code, etc. Any would probably be fine, imho.
Hash map would be my initial implementation, though, if only because I don't know where it would be used, and the map will be immediately understood.
Well, I guess not everyone is an amazing genius like you.
Plus I'll never wear leather pants. That can't be comfortable.
I know some coworkers who will intentionally ask a question they know you were asked in a previous interview to test your integrity. (Edit: Not that I would condone this practice either.)
These types of interview questions are about evaluating how you think far more than what you know. So, more importantly than the risk of getting caught, if you recite an answer from memory and pretend that you're deriving the solution on the fly, you're lying to your future coworker.
That doesn't make any sense.
open != honest. Two different things. It's not dishonest to obey a Non Disclosure Agreement, and so you can be perfectly honest person and still not be "open" about matters which you are not authorized to reveal.
"Not talking about your past interview experience" has about the level of openness as "not talking about your corporate experience".
Where do you draw the line? What if you'd spent the previous two days reading about graph theory and in doing so had come across a neat network flow problem that co es up almost verbatim in the interview? What's the difference?
Interviews are a filter and not necessarily always accurate or fair. This can go both ways. You can have bad days when your brain freezes. You can have good days when you're asked something you know in your sleep. It doesn't really matter how you know it.
Besides just knowing the solution to something doesn't mean you can give the answer, discuss the solution and analyze other solutions, all of which may come up.
That's sort of like saying you won't shot a man in the back during a war.
No one came forward - the professor only figured it out after he saw the average mark on the test was one-and-a-half grades higher than normal.
Your mileage may vary.
Most large company hiring practices are not so much a selection of specific traits as they are a filter for ensuring a lack of negative traits. When you factor in the bias of narcissism in interviewers, you'll get competent people who are skillful at reflecting the interviewers' traits back at them (such as the author, who didn't demonstrate incompetency with his first answer, but aced the interview by reflecting the cleverness the interviewer must have self-identified with as "Google material".) After a certain point, four or seven or nine layers of interview will certainly guarantee the incompetent ones don't get through, but at the same time it will also select for the kind of highly adaptable social personality that is often found in political operators.
I saw something similar with a badly underqualified sys-admin who had been in marine recon before embarking on a technical career. He had zero issues finding a high paying job.
I read a book called "Money Ball" last year. One of the lessons I took away is that a successful baseball team can be created from undervalued stats (i.e. irrational beliefs in value cause inefficiencies). This trend you described forms teams of walkers xor home-runners, for example. I don't know why I believe this (I'm subject to my own criticism), but I strongly believe teams with multiple talents outperform teams with one talent (generalists vs niche).
Minutes? Well, yes.
In interviews, my tentative conclusion after two minutes is _usually_ the same as after 60 minutes. (I spend the following 58 minutes trying to disprove my hypothesis, of course.)
One of the most interesting questions given to me was, write an algorithm such that given four colors and a rectangle, fill the rectangle with a gradient using a color in each corner. After the fact it wasn't very hard, but having never thought about such a problem, it was pretty difficult white boarding it out. It was a pretty good question because I think that most people aren't thinking or preparing for such a problem, instead opting to study arrays, linked lists, trees, sorting algorithms and running time. You really get to see how a person thinks with it.
I got the job.
I can solve the same problem by using statistical thermodynamics, and show its only o(1), since each string is a configuration of the system and finding common alphabets is like finding degenerate states.
How many stories like this are out there now? Hundreds?
I realise that this is a bit of redundant post .. but, as a person who isn't a brilliant coder I surprised myself. But then again, after reading the comments here - I think maybe I just have an obtuse way of thinking about things.
i think what matters is that characters are enumerable, not finite?
Maybe we'll get there someday...