I'm curious to know why calling a phone number was a deal-breaker.
It seemed eminently likely (to me) that it would be an automated system, but, even if it wasn't, talking to someone isn't that big a deal to me. I certainly wasn't concerned about long-distance charges, but I suppose that might be a problem for some.
I thought it was a nice little twist in the problem set.
but, even if it wasn't, talking to someone isn't that big a deal to me.
A lot of people struggle with the phone. I certainly have, though I'm getting better at it. I've noticed many people become spookily compliant on the phone, endlessly listening to and being polite to even the most annoying callers instead of just hanging up.
I live in Norway, so the phone bill is a significant factor. Also, the wife and kids are sleeping in the next room, which would require me to step outside on the porch in the middle of the night with my cellphone.
Yet also, I'm so tired I couldn't have englished very well in my phone anyway. :-)
Well, I was suggesting looking for symmetrical triads (or repeating characters) and then working outward. I'd say the eye is pretty good at picking out symmetries.
Why aren't you guys just searching for the palindromes?
There's more efficient ways than doing every character, or groups of them... What constitutes a palindrome? What does that mean to simplify what we're doing?
Brute works here because of bad test case. Author could have generated a smart test case and then optimal algorithm could be using suffix array which takes O(n), brute would take O(n!). However a bit smart brute gave the answer in approx 3-4 minutes ( computation + coding time). And yes, Python FTW.
Isn't brute force just O(n^3)? Loop over each character to start potential palindrome, loop from start character to end, reverse substring and compare. But yeah, the test input should be longer and/or smarter. Ditto on the third problem.
I was in the middle of thinking through the algorithm when I looked at it and saw the password in the text --- the password worked but I still want to code the algorithm later to confirm.
That's sort of what I mean here. It's like solving a wordsearch puzzle. There can't be more than a couple dozen strings with structure xyx, or xyyx. Find them by eye and work outward and see if it's zxyxz, and so on. Decided to make this process into my algorithm.
Four score and seven years ago our faathers brought forth on this containent a new nation conceived inz Liberty and dedicated to the proposition that all men are created equal Now we are engaged in a greaht civil war testing whether that naption or any nartion so conceived and so dedicated can long endure We are qmet on a great battlefiemld of tzhat war
Never mind that finding the actual text, removing the spaces and caps, and running diff would probably take longer than coding and executing a brute force algorithm :P
Ruby was my main choice + some command line tools to do bits of extra work, like 'sort' to find the largest palindrome and 'wc' to count the results in last exercise, and even Python command line to just manually sum the primes in second exercise.
I can't take credit for the solution I posted though.
I originally wrote a naive O(N^2) complexity solution (which was much shorter and was fine for the length of the input) I had this palindrome code in my 'toolbox' of code I've come across though, I'm afraid I don't know the orig author.
I just tweaked it as this is more in line with the type of example you're looking for.
Interesting, I'll have to go over your code fairly carefully, as I'm not familiar with every technique you're using here for performance.
I've since learned a good deal about Clojure and implemented an idiomatic (but probably less performant) version, for anyone interested in how short this can be:
I used Lua, myself. I briefly considered using a more featureful language like Ruby, but I'm happy to say that Lua did the job just fine. I made good use of coroutines for the second and third problems.
I used Haskell for the first one (was my first actual Haskell program, everything before was just xmonad config), C for the second one (already had the needed code for generating fibonacci sequences and a prime number sieve from when I went through the euler problems using only ANSI C) and Perl for the last one. I initially used Data::PowerSet for the Perl code, but decided to write my own after it took several minutes to build the combinations and I discovered that I had the wrong answer because I improperly read the problem.
I should note that I used the existing C code I had because I had no idea where they would intersect and didn't feel like writing Yet Another Arbitrarily Large Integer Handler.
I know I'm late to the party, :)
I used Ruby 1.9.2. It's funny that it's the first time I used the combination generation method built in Ruby Array. The whole three questions took me about a bit more than 20 minutes, a bit longer than I thought tho.
The last question isn't that difficult if you brute force it and have loads of memory. I tried to do it in python using itertools on my work thinclient and got a memoryerror. If you however break up your combinations.. you're good to go!
int[] nums = {...}
for i = 1 to (2^length(nums) - 1)
int[] possibility = { nums[x] where (2^x bitand i) > 0 }
test possibility and perhaps increment hit counter
I was at work on a crappy thin client and first tried to run list(itertools.combinations(sequence)), which was crapping out. After I switched it to itertools.combinations(sequence,i) and put that right into my for loop it was fine.
I don't think trivializing the combinations with Python's builtins, looking up the fib primes with OEIS, or computing factors with Alpha is cheating. I hope, in fact, it's the whole point of the exercise: choose the right tools for the job. If you're writing code to test primeness or generate Fibonacci numbers, I sure as hell don't want to hire you.
Elegant, but inefficient if you want to get exact values for large n. You're much better off using doubling operations. If you forget those, you can remember them from the matrix version. If fib(0) = 0. fib(1) = 1. etc. Then
n
[0 1] = [fib(n) fib(n+1)]
[1 1] [fib(n+1) fib(n+2)]
With repeated squarings, you can efficiently generate any Fibonacci number you want.
Here (where you have to search through Fibonacci numbers) I suspect memoization is rather the way to go:
# memoized fibonacci function
fibtable = {1:1, 0:1}
def fib (n):
global fibtable
if n in fibtable.keys():
return fibtable [n]
val = fib (n-1) + fib (n-2)
fibtable [n] = val
return val
If you're writing code to test primeness or generate Fibonacci numbers, I sure as hell don't want to hire you.
Maybe you should have called it the "Greplin Challenge," then, instead of the "Greplin Programming Challenge." It's not a real task, after all; the reward comes from accepting a completely artificial challenge. I'm going to do the challenge before dinner tonight, and before I leave work I could get source code for the solutions from the guy down the hall from me who did the challenge as soon as it was posted -- and you certainly don't want to hire a guy who recodes other people's work for no reason, right?
Maybe we have a different hiring mindset than dschoon - we're equally happy with people who find the answers or create the answers. In a production system, we certainly wouldn't want hand-rolled primeness checking. But in a programming challenge, we think it's fun to write it for yourself.
I wrote extremely naive Ruby algos from scratch that solved the problems in a couple seconds, or in the case of the last problem, a couple of minutes. I'm sure the whole challenge would have taken longer if I tried to use any dependencies.
I'm usually pretty bad at these kind of challenges (lately I tried registering at one mind-challenges site, but I couldn't even get past the five entry-level questions, which would have allowed me to even register), but this was surprisingly easy. Simple brute-force methods worked for each of the three tasks. I was totally surprised that the first time I entered the answer for each of the tasks, it was indeed the correct one.
But then again... these are all pretty standard computer science problems, nothing that I hadn't in some way done before.
On a side-note: Interestingly I used recursion for each of the three problems. Well... actually for the primes-problem I got stack overflow and rewrote it to not use recursion, but still, at least in principle :=)
Agreed - I was laughing as I was writing some of my code because it was so bad. These sort of questions are designed around algorithm design, but a one-off problem with these small of sample sets doesn't need an elegant solution - a hatchet job does just fine. I'm not a CS grad and my math skills are a bit iffy, but I was able to solve all three challenges in a pretty reasonable amount of time.
Damn, I have to go in to work early today or I could continue this. The first one only took a minute or two of coding to solve in Perl. The search string was several times longer than my code, even with use warnings & use strict in there.
I'd write a bit of code to memoize the function before I'd do the Fibonacci numbers, though, and I just don't have time to continue right now, even though it's pretty easy. Are the rest of the tests like that? Do they force you to use more efficient code, rather than simpler brute force tests so that your code has a decent runtime?
I immediately went to Wikipedia, found out what type of CS problem the first challenge was, then followed the external links at the bottom of the page to find the Perl module I needed and installed it from CPAN.
I quit because this seemed like cheating but now I'm thinking... Maybe it was the point? To see if I would try to find something off-the-shelf to solve the problem quickly. Still not sure it was, because if so the challenge certainly doesn't demonstrate that I have any CS chops. :-\
I seem to recall that there were 2^22 sets in the power set of that list of numbers, so you obviously had to use some kind of technique to cull the vast majority of the sets.
Hmm... now that I think about it, did you do something like starting at the end of the list, then subtracting numbers as you went until you either found a set that added up to your top number, or found it impossible for that number to be in the set?
It seems like it would take a lot of paper to do that, but it's more efficient than the simple brute force technique I did.
I'm just curious, because I bet there are better ways to do that one and I think the challenge is probably over by now.
I'm pretty sure that cperciva used a similar trick, but in each row you're potentially adding another element of the set, and not potentially adding 1.
This gives you a mapping telling you how many ways there are to get 0, 1, 2, 3, etc as the sum of some subset of the set. Just sum this over the set, and subtract the size of the set. (Every element in the set is the sum of itself, but you don't want to count those.) And there is your answer.
How do you go about solving #2 on pen and paper? Well, calculating the Fibonacci sequence, ok. The sum of prime divisors of X+1, I guess... though it gets slightly harder for me after dividing by 2, 3 and 5. But how do you know for sure that X is prime?
Based on bd's link, I'll just assume that you have super powers. (or I'm approaching the problem the wrong way)
edit: I was starting to think about what to write for #1, but ended finding the answer by looking at it as well.
You can use the Sieve of Eratosthenes to generate primes with pen and paper very easily. Or, you could find a roll of paper and evaluate any computable function (assuming unbounded paper). ;)
It doesn't seem to make it especially easy: you still have the same problem of having to eliminate the multiples of 61, 79, 89, etc. which are not obvious. Yes, you can count, but it looks very time-consuming.
The problem still stands that one needs to go in the 500,000s for that problem (thus 700s for the square root). That's still a long way to go…
I'm really curious about how cperciva did it. You're supposed to find the first Fibonacci prime over 227,000. The first Fibonacci number over that is obviously not prime (multiple of 3), but the one after that is not obvious even if you have the list of primes obtained with that method.
You have less than 30 Fibbonacci numbers to compute.
That 317811 is divisible by 3 is obvious upon adding its digits together.
Once you've verified that 514229 isn't divisible by a handful of small primes, you don't try to prove primality. Instead factor 514230 and stick it in. After dividing by 2, 3, and 5, you've got 17141. It doesn't take that long to run through 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59 and 61. At which point you have an answer you can try plugging in to discover it is correct. Which is a sequence cperciva pretty definitely has memorized. (I do.) Or alternately cperciva may have better factorization techniques memorized.
If you already have a routine around for factoring (I do), then this takes longer than coding it. But I could do it with paper and pencil pretty easily.
Fair enough. Though I'd argue on "entirely solvable by pencil and paper", since the answer is an educated guess in that case and the proof that it's correct resides in checking with the webpage. ;-)
To be honest, in the same amount of time, one could also estimate the range where the answer should be and plug it one by one in the form until it validates. (which we'll call a less educated guess :))
That's pretty frail. It won't catch palindromes with an even number of letters (e.g. ababbaba) and it'll only find those of at most 7 characters. Granted, you can use those matches to work outwards and search for more, but I didn't think the general solution was all that hard.
Oddly enough, it didn't even occur to me to try a regex and I like using them quite a bit.
I solved all three problems in under a half-hour by writing quick-and-dirty Java programs to do it. The standard libraries provide almost everything I needed; the only thing I used other than that was Maple to factor the number. I'm pretty sure mucking around with CPAN libs such would have taken me longer. Granted, my solutions were brute-force and not very elegant, but for simple problems like these with small inputs I can write code to solve it faster than finding the answer elsewhere.
I'm disappointed that it is possible to solve by hand, as that undercuts the reward. This is one of the great aspects of ITA's programming problems: none of them are even solvable by brute force.
Writing code for 2 & 3 would probably take more than solving it with pen&paper, for me at least. I wrote code for #1 because it was practically 3 lines..
If it was really meant as a programming challenge, it should feature problems which are worth writing code for.
damn it had a typo in the fib generation for the second number and lost a lot of time trying to factor a _massive_ number that was obviously the wrong one :)
I've generally done well on job-interview programming challenges and gotten interviews afterwards. But looking on these quiz things, I'm still frustrated by them.
You see, all the "ordinary" question involved in job-fitting still have to be asked and answered so sometimes I've done great in ability part only to have really basic "culture" or requirements issue hit later when they could have been caught immediate.
And so, even though I've enjoyed and learned something on these quizzes, the employer who begins a relationship with a quiz seems to be saying they can demand some piece of my time without any investment on their part and this isn't setting a tone reciprocity, something I'd look for in a future employer.
That was fun, good waste of time while my code was compiling. I just used C++ and hacked up a prime seive for #2 and for #3 used a combination generator I had previously used before - http://photon.poly.edu/~hbr/boost/combinations.html
Not always is "exponential" a bad thing. For small sets, the expo algorithm is actually faster than the polynomial one. Although yeah, generally speaking, it's a bad idea.
I tried on #3 the most inefficient algorithm I could come up with - blindly going through all possible combinations and checking if their biggest member is equal to the sum of the rest. Time of the execution: 0.6s
I am not sure if this step of allowing the "shortcuts" was part of the game or not. All that would had to be done is to give 128 elements of the array to exclude at least the most blatant brute-forcing.
I think this would've been a better filter for hiring if the magnitude were larger (e.g. huge string, more numbers for the combination, etc) or if there was a strict time limit. As it is right now, I don't think the hardcore hackers you're looking for will be that enticed.
I think that you'd be surprised at the sheer number of applicants a very basic programming challenge can weed out. The company that I work at has a simple test to parse a csv file and a surprising amount of people who appear to be good candidates bomb it.
What about a puzzle system system -- Companies can post/host questions and then review the answers. I've drafted a quick blog post if anybody wants to comment more directly... Maybe I'll make it this weekends projects (since my frid.ge clone was killed by Facebooks new groups).
166 comments
[ 2.8 ms ] story [ 205 ms ] threadEdit: Excellent! Back to hacking.
It looks like the number is a landline in the Bay Area. I wonder if some poor soul at Greplin will be taking calls all day.
For what it's worth - it's just a Twilio app - we thought it would add to the fun.
It seemed eminently likely (to me) that it would be an automated system, but, even if it wasn't, talking to someone isn't that big a deal to me. I certainly wasn't concerned about long-distance charges, but I suppose that might be a problem for some.
I thought it was a nice little twist in the problem set.
A lot of people struggle with the phone. I certainly have, though I'm getting better at it. I've noticed many people become spookily compliant on the phone, endlessly listening to and being polite to even the most annoying callers instead of just hanging up.
Yet also, I'm so tired I couldn't have englished very well in my phone anyway. :-)
There's more efficient ways than doing every character, or groups of them... What constitutes a palindrome? What does that mean to simplify what we're doing?
http://www.w3schools.com/jsref/jsref_obj_string.asp
D'oh! My is_palindrome(word) just got a lot shorter, thanks :)
Try this:
Choose the start and end indices. Then take a slice to see if it's a palindrome. Nice and speedy! :)Four score and seven years ago our faathers brought forth on this containent a new nation conceived inz Liberty and dedicated to the proposition that all men are created equal Now we are engaged in a greaht civil war testing whether that naption or any nartion so conceived and so dedicated can long endure We are qmet on a great battlefiemld of tzhat war
I decided to try a different one on each level, so I used Python, bash (letting GNU coreutils 'factor' do the hard work), and Haskell, respectively.
http://gist.github.com/621130
I can't take credit for the solution I posted though.
I originally wrote a naive O(N^2) complexity solution (which was much shorter and was fine for the length of the input) I had this palindrome code in my 'toolbox' of code I've come across though, I'm afraid I don't know the orig author.
I just tweaked it as this is more in line with the type of example you're looking for.
I've since learned a good deal about Clojure and implemented an idiomatic (but probably less performant) version, for anyone interested in how short this can be:
http://gist.github.com/635674
I should note that I used the existing C code I had because I had no idea where they would intersect and didn't feel like writing Yet Another Arbitrarily Large Integer Handler.
Quick and dirty solutions here: http://gist.github.com/618006
None of my solutions were particularly elegant :-)
And for part 3 I used prolog. About ~6 lines or so.
Fun, made my day. Good idea greplin dudes!
I would be curious how many people did you lose because of phonecall requirement (before you changed it).
Also CSV for just a list of 22 numbers wasn't really necessary.
If you do web puzzle, the best is to keep everything self-contained, no downloads, no using external channels, just copy and paste.
FYI another Python cheater here (+Wolfram Alpha & Wikipedia, I'm lazy :).
int((1/math.sqrt(5))*(math.pow(((1+math.sqrt(5))/2),fibonacci)-math.pow(((1-math.sqrt(5))/2),fibonacci)))
Reference here: http://mathproofs.blogspot.com/2005/04/nth-term-of-fibonacci...
Maybe you should have called it the "Greplin Challenge," then, instead of the "Greplin Programming Challenge." It's not a real task, after all; the reward comes from accepting a completely artificial challenge. I'm going to do the challenge before dinner tonight, and before I leave work I could get source code for the solutions from the guy down the hall from me who did the challenge as soon as it was posted -- and you certainly don't want to hire a guy who recodes other people's work for no reason, right?
It was way more fun to do it from scratch :D
Thanks grepplin
p.s. the csv was copied in my [] python list :)
var nums = "3, 4, 9, 14, 15, 19, 28, 37, 47, 50, 54, 56, 59, 61, 70, 73, 78, 81, 92, 95, 97, 99".split(", ");
for(var i = 0;i< nums.length;i++) { nums[i] = parseInt(nums[i],10); }
Instead of just editing the numbers so that it was an array right away. Happens if you code before you think :-)
But then again... these are all pretty standard computer science problems, nothing that I hadn't in some way done before.
On a side-note: Interestingly I used recursion for each of the three problems. Well... actually for the primes-problem I got stack overflow and rewrote it to not use recursion, but still, at least in principle :=)
I'd write a bit of code to memoize the function before I'd do the Fibonacci numbers, though, and I just don't have time to continue right now, even though it's pretty easy. Are the rest of the tests like that? Do they force you to use more efficient code, rather than simpler brute force tests so that your code has a decent runtime?
Coming back, I see that I really don't need to be very efficient for any of these problems, which I honestly find a little disappointing.
I quit because this seemed like cheating but now I'm thinking... Maybe it was the point? To see if I would try to find something off-the-shelf to solve the problem quickly. Still not sure it was, because if so the challenge certainly doesn't demonstrate that I have any CS chops. :-\
Spoiler alert: I believe this module will do the trick http://search.cpan.org/~gray/Tree-Suffix-0.21/lib/Tree/Suffi...
http://news.ycombinator.com/item?id=35083
I wish I had discovered HN back then.
Hmm... now that I think about it, did you do something like starting at the end of the list, then subtracting numbers as you went until you either found a set that added up to your top number, or found it impossible for that number to be in the set?
It seems like it would take a lot of paper to do that, but it's more efficient than the simple brute force technique I did.
I'm just curious, because I bet there are better ways to do that one and I think the challenge is probably over by now.
I'm pretty sure that cperciva used a similar trick, but in each row you're potentially adding another element of the set, and not potentially adding 1.
This gives you a mapping telling you how many ways there are to get 0, 1, 2, 3, etc as the sum of some subset of the set. Just sum this over the set, and subtract the size of the set. (Every element in the set is the sum of itself, but you don't want to count those.) And there is your answer.
Based on bd's link, I'll just assume that you have super powers. (or I'm approaching the problem the wrong way)
edit: I was starting to think about what to write for #1, but ended finding the answer by looking at it as well.
The problem still stands that one needs to go in the 500,000s for that problem (thus 700s for the square root). That's still a long way to go…
I'm really curious about how cperciva did it. You're supposed to find the first Fibonacci prime over 227,000. The first Fibonacci number over that is obviously not prime (multiple of 3), but the one after that is not obvious even if you have the list of primes obtained with that method.
That 317811 is divisible by 3 is obvious upon adding its digits together.
Once you've verified that 514229 isn't divisible by a handful of small primes, you don't try to prove primality. Instead factor 514230 and stick it in. After dividing by 2, 3, and 5, you've got 17141. It doesn't take that long to run through 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59 and 61. At which point you have an answer you can try plugging in to discover it is correct. Which is a sequence cperciva pretty definitely has memorized. (I do.) Or alternately cperciva may have better factorization techniques memorized.
If you already have a routine around for factoring (I do), then this takes longer than coding it. But I could do it with paper and pencil pretty easily.
To be honest, in the same amount of time, one could also estimate the range where the answer should be and plug it one by one in the form until it validates. (which we'll call a less educated guess :))
Oddly enough, it didn't even occur to me to try a regex and I like using them quite a bit.
If it was really meant as a programming challenge, it should feature problems which are worth writing code for.
I think Clojure might've made things a tad easier (given all its sequence functions), but I'm just learning it, so Ruby all the way.
That said, finding the palindromes in Ruby took me about 12 lines of code (less if I didn't structure it using methods).
You see, all the "ordinary" question involved in job-fitting still have to be asked and answered so sometimes I've done great in ability part only to have really basic "culture" or requirements issue hit later when they could have been caught immediate.
And so, even though I've enjoyed and learned something on these quizzes, the employer who begins a relationship with a quiz seems to be saying they can demand some piece of my time without any investment on their part and this isn't setting a tone reciprocity, something I'd look for in a future employer.
Congratulations, you just used an exponential-time algorithm for a polynomial-time problem.
I am not sure if this step of allowing the "shortcuts" was part of the game or not. All that would had to be done is to give 128 elements of the array to exclude at least the most blatant brute-forcing.
Here is my Part 1 implemented in Ruby. http://gist.github.com/617566
http://bit.ly/b6GC6F
Seriously though, this is awesome. I'd love to know how you guys do in terms of # of applicants and the end-result (any hires?).