A religious discussion of sorts
Jun. 18th, 2009 10:27 pmI got an email today from one of the super secret stealth start-ups, the one I really wanted, and they told me that they had chosen to go with another candidate. Bummer.
At one recent interview, an engineer asked me to “give him the sum of the two highest digits in an integer array. Any language.” I thought for a moment, then wrote:
array.sort() return array[-1] + array[-2]
He said that was fine, but since it would be O(n*logn), could I do it in O(n). He wanted a linear search instead.
After answering the question to his satisfaction, we got into a bit of a religious discussion about the merits of concentrating on performance during initial composition, versus concentrating on correctness. I’m much more a “get it working, then get it right, then profile the working program for bottlenecks and work them out.” It is possible that you can create systemically slow solutions that’ll require a re-write, but that’s actually far less likely than having I/O or CPU bottlenecks in small functions of code that can be fixed with optimization.
He later told me that, although I didn’t get the job, he voted to hire me. He liked my answers and appreciated that I was willing to stand my ground and discuss the relative merits of different approaches.
This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
no subject
Date: 2009-06-19 06:18 am (UTC)no subject
Date: 2009-06-19 07:15 am (UTC)list.sortis native, whereas the alternate solution involves an expensive interpreted loop.no subject
Date: 2009-06-19 01:59 pm (UTC)no subject
Date: 2009-06-19 03:57 pm (UTC)no subject
Date: 2009-06-19 04:08 pm (UTC)no subject
Date: 2009-06-19 05:54 pm (UTC)no subject
Date: 2009-06-19 06:34 pm (UTC)The real problem is that the obvious schemes for doing that take O(n) additional space; I suspect you might not be able to do it in n+log(n) comparisons and constant additional space, but I can't say for sure either way offhand.
no subject
Date: 2009-06-19 06:41 pm (UTC)no subject
Date: 2009-06-20 10:18 pm (UTC)in O(n) time. :-)
(Also, this uses O(constant) additional space.)
I hope this is slightly amusing...
- -
def find_maxes(a): """Returns second-greatest and greatest members of a.""" if len(a) < 2: raise 'insufficiently long array' # deprecators of string exceptions can suck my left nut # until I get a spec. if len(a) == 2: return a maxes = [a[2]] + a[:2] # After any sort call, # holds second-greatest and greatest value # found so far, # *preceded* by current candidate value. for x in a[2:]: maxes[0] = x maxes.sort() print maxes return maxes[1:3] def find_maxes_sum(a): return sum(find_maxes(a))no subject
Date: 2009-06-19 02:09 pm (UTC)I've only just started playing with multithreading. Do you have any pointers on that?
And for some reason...
Date: 2009-06-19 05:49 pm (UTC)But I agree, get it right, see where the actual instead of theoretical bottlenecks are, and break those open.
no subject
Date: 2009-06-20 12:22 am (UTC)I think your code will throw some kind of exception (given array=[]). But throwing exception is not the same thing as returning a sum.
Anyway, this is the kind of response I give, because this is the kind of response that makes me recommend hiring when I'm asking the questions. Programmers simply cannot be too meticulous.
no subject
Date: 2009-06-20 04:42 am (UTC)no subject
Date: 2009-06-20 05:14 am (UTC)I will tolerate arbitrary amounts of pedantry from candidates, in fact I love it, because it exposes intelligence. If someone is pedantic but not very bright, it's easy to find the limits of their intelligence in a Socratic manner. I particularly like someone correctly pointing out issues in something I've told them, as that also shows confidence. It's a necessary skill for work, after all.
no subject
Date: 2009-06-20 05:55 am (UTC)no subject
Date: 2009-06-22 03:40 am (UTC)Rather than performing comparisons to find the two largest integers in the array, consider instead finding the largest sum, and then "auto-pull" the two largest integers.
Something along these lines (sorry, I think in C):
extern int array[]; extern int alen; register int cur, test, sum; int max1, max2; int i; if (alen < 2) return (-1); /* Array too short. */ else if (alen == 2) return (array[0] + array[1]); else { max1 = array[0]; max2 = array[1]; sum = max1 + max1 + max2; for (i = 2; i < alen; ++i) { cur = array[i]; test = cur + max1 + max2; if (test > sum) { sum = test; /* * Replace the smaller value. */ if (max1 < max2) max1 = cur; else max2 = cur; } } } return (max1 + max2);Note: I have not actually tested the code above. And given the number of additions, subtractions, and comparisons it performs, it's not at all clear whether it's superior to any other approach. But it does fetch each array element only once.
The Computing World Isn't What It Once Was
Date: 2009-06-23 08:41 am (UTC)Since then I've come around to having megabytes of space available for programs and data, and that throwing faster h/w at a problem is often cheaper than rewriting it because the chances are that the hardware in question is already idling more than computing, and memory limits don't really exist for most programs. If it's too slow that can be fixed after it's running.
The one thing I would have done differently with your solution would have been to add a comment line above it:
//compute and return the sum of the two largest array values
...
Even on a 2-line solution that is the way I write my code - and it often catches the examiner by surprise.
--DB_Story
Re: The Computing World Isn't What It Once Was
Date: 2009-06-26 06:25 pm (UTC)