Seems like I may be the only person to have used a bioinformatics approach to the first problem! bl2seq to the rescue!! I'll explain my approach if anyone seems interested... as I am not sure if posting solutions is acceptable here.
Edit: As others seem to be posting gist/snips etc. so I guess it is OK.
Step 0 - Copied parent string to file: p1.txt
Step 1 - Used python to reverse the entire string and copy to second file: cat p1.txt | python -c "print raw_input()[::-1]" > p2.txt
Step 2 - Formatted the two files, so as to be parsed as FASTA, by adding sequence name headers.
Step 3 - Use bl2seq (blastp) locally or online to align the two "sequences".
Final alignment shows only one major chunk of identity, i.e. the answer.
So, in essence, a dynamic programming algo would work.
If bl2seq gets the longest common subsequence I did exactly the same thing. In haskell it just seems the right thing to do. Actually it would be damn interesting to see if there are patterns in the solutions for every programming language.
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.
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.
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
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 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.
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. :-\
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.
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 :))
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.
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.
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.
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.
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'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.
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. :-)
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 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.
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 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 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.
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:
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
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'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.
I'm a little bored with Project Euler after solving the first 40+ problems with brute force or near-brute force algorithms. If I wasn't using it to learn a new language, I would have quit already. As it is, after solving one problem I usually quit for the day instead of moving on to the next. When do the problems pick up?
Well that depends on your level of expertise :-) I start to have unsolved problems around #60, but found I had to start getting pretty clever long before that. The highest number I've solved is 112, and the one before that is 102. YMMV.
I didn't see the point in doing this in anything but C. I tried it without cheating, and to make it as interesting to myself as possible. Also did it after a week of writing briefs, so that was a nice way to unwind from that! Pretty Fun.
Anyway, if I'm applying for a job (which I wasn't), the last thing I'm going to do is send in a bunch of one-liners.
This really doesn't reflect a programmers skills in anyway. I managed to write ruby to solve the problems, but I approached it to do for fun. Brain teasers aren't going to weed out the good from bad.
Also, considering the instructions explicitly say "write code to..." I would say using tools that give you the answers is in fact cheating. It's like math test where you have to show your work.
IMHO, these contrived puzzles, while fun, are really unrealistic and don't map well to problems you'll encounter on the job which requires knowledge, experience and creativity and do not have just one answer.
Of all of the jobs-page challenges, thesixyone's is probably the most practical and I've seen:
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).
I can't read ruby, but here's something a little smarter than brute force in C (on its way to DP, but I couldn't be arsed to work out the recurrence so I just iterated until it stabilized): http://gist.github.com/617854
It looks similar to mine, but you got lucky (or unlucky depending on how you look at it) that the longest palindrome had an odd character count.
The confusing bits in the Ruby are actually just the definition of an even and odd palindrome finder, which are the same except for two seed values for where the first comparison is conducted and it's length.
Took < 10 minutes. The problems were very, very easy. If they expect people to take 1-2 hours and have trouble with this, then the message that I would take away from this is that their hiring bar is quite low.
http://codepad.org/rdSirAkD -- Solution to third problem in 26 lines of ruby _without_ using combinations. It's pretty fast too, gives the answer in 0.020s.
I see that you did brute force primality testing, too. Am I the only one who at least only divided by odd numbers (and two) in their brute-force is_prime function? Technically, you only need to test divide by all primes less than or equal to sqrt(n), after all.
I guess I could have used a faster primality test, but I didn't feel like writing anything that complex. I know there's a website out there that has a test that works for anything under about 10 billion, if memory serves, by using the probabalistic tests and doing a special check for the only exception. Heck, it even gives you the factors for the largest number in its range...
Thanks for sharing!
Love the style and it's readability. My newbie python code did the trick, but is way harder to read - your code really showed me room for improvement!
I did the naive implementation for problem 1. (double loop, O(n2)), in Javascript. Took chrome about 1 minute to compute the comparisons of all strings. I'm so lazy.
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?
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.
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.
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 :)
numbers ="3,4,9,14,15,19,28,37,47,50,54,56,59,61,70,73,78,81,92,95,97].split()
numbers = [int(i) for i in numbers]
def sum_eq(lst,k):
total = sum(lst)
if total == k or k==0:return 1
elif total < k or len(lst)==1:return 0
else:
n1,nr = lst[0],lst[1:]
return sum_eq(nr,k-n1) + sum_eq(nr,k)
def sum_all_eq(lst):
total = 0
for k in range(1,len(lst)):
total += sum_eq(lst[0:k],lst[k])
return total
Problem 1: 2 minutes for 5 lines of PHP code. Problem 2: 1 minute of Google and Google (why reinvent the wheel?). Problem 3: half a minute of brainwork, 15 minutes worth of tedious PHP snippet.
I got the impression that this particular test was not a good one for finding apt programmers. The questions and the solutions were just so very "off".
Edit: As others seem to be posting gist/snips etc. so I guess it is OK.
Step 0 - Copied parent string to file: p1.txt
Step 1 - Used python to reverse the entire string and copy to second file: cat p1.txt | python -c "print raw_input()[::-1]" > p2.txt
Step 2 - Formatted the two files, so as to be parsed as FASTA, by adding sequence name headers.
Step 3 - Use bl2seq (blastp) locally or online to align the two "sequences". Final alignment shows only one major chunk of identity, i.e. the answer.
So, in essence, a dynamic programming algo would work.