11 ms·
Interviewing programmers: coding test example explained
- cperciva 16y agoSo when do we get to read part 3? I want to see what "creative" solutions people came up with.
- RiderOfGiraffes 16y agoCurrently working on that. It's safe to say that your two solutions were the most creative. In my graph of solution proximity, they are both a long way away from all the other solutions.
- cperciva 16y agoAwww. I was hoping that with an audience of hackers and such a trivial problem I wouldn't be alone in my creativity. :-/
- levesque 16y agoIf you want 'creative' solutions to problems you might want to check out google code jam archives. During the qualifications this year someone wrote a solution in lolcode. Was quite interesting.
- JoachimSchipper 16y agoWith regards to your trivia question, where you talking about http://decode.org/?q=pbagvahr http://decode.org/?q=pbagvahr?
- RiderOfGiraffes 16y agoIf I understand you correctly, yes.
- grogers 16y agoInteresting, when I solved the problem originally on my own, I got to the exact same solution just with different variable names and braces. I suspect that this is probably the most common way to solve it.
- aplusbi 16y agoYeah, I had almost exactly the same code. I'm sure most people did too. The only other "obvious" algorithm is the n^2 one.
- RiderOfGiraffes 16y agoYou will be surprised.
- aplusbi 16y agoI like surprises! Looking forward to part 3...
- Xurinos 16y agoI use do...while instead of the for loop, making the usual nasty C-programmer use of ++ in the right spots, but other than that, my solution is the same. Edit: Correction... I also copy the '\0' character before exiting instead of making that a separate step. It has to do with the order of things. Here is the code: char* read_ptr = s; do { if (*read_ptr != c) { *s++ = *read_ptr; } } while (*read_ptr++ != '\0');
- philwelch 16y agoYou can use an inner loop to skip over removable chars in the source string but I didn't think that was n^2. (Code below for reference.) Am I wrong that my solution is n, or is there another obvious n^2 algorithm? void condense_by_removing( char *z_terminated , char char_to_remove) { char * sp; char * dp; sp = dp = z_terminated; while (*sp != '\0') { while (*sp == char_to_remove){ sp++; } *dp = *sp; dp++; sp++; } *dp = *sp; }
- js2 16y ago1) In TFA, s/cersion/version/, but that's an amusing typo. :-) 2) Initializing inside the for loop requires C99; is that to be considered idiomatic? I didn't think so. I'll be curious how many submissions were either identical to your suggested idiomatic solution or its K&R equiv: https://gist.github.com/3f4daf24595788258a01 https://gist.github.com/3f4daf24595788258a01 :-)
- RiderOfGiraffes 16y ago1) In TFA, s/cersion/version/, but that's an amusing typo. :-) Bother - now fixed. Thanks.
- JoachimSchipper 16y agoAlthough I'm not sure "its K&R equivalent" is correct (that's C89 and has "modern" function implementations), C99 is indeed not that common. If only because many compilers don't support it (including Microsoft's).
- js2 16y agoBah, I learned my C from K&R 2nd ed. I guess that's not K&R C, is it? :-)
- JoachimSchipper 16y agoIt's... complicated. K&R 2nd ed. (which is an excellent book!) is based on a draft of ANSI C; pre-ANSI C was not standardized but rather based on an informal reading of K&R 1st ed., hence "K&R syntax" and the like. At least, if I recall correctly.
- roel_v 16y agoAm I OCD when I cringe when I see 'p_rite' where he (I think) means 'p_write'? That alone would knock a few points off a candidate doing this test when he's interviewing with me. 'rite' can mean 'write' or 'right' or even 'allright' - why the unnecessary confusion?
- tptacek 16y agoYou're not alone in feeling the OCD twinge, but are almost certainly alone in being willing to demerit a candidate writing that.
- sfphotoarts 16y agoI believe the intent was not to misspell (because clearly given one side of the coin being 'read' the word 'rite' is clearly meant to be its counterpart) but was to make for neat alignment of the variable declarations. char w, r might have been easier and less twinge inducing, but I think it important to correct the misgiving that the person writing 'rite' was not misspelling but making a deliberate choice to align their variables. His own form of OCD, a trait common in good programmers.
- Maro 16y agoActually, he's not alone in demeriting =)
- mynameishere 16y agoWhy would he be alone? Why is spelling less important in code than in normal writing? I would argue it is considerably more important.
- tptacek 16y agoIf you truly think the market for C developers is so favorable to employers that someone who can write the in-place-whitespace-removal function off the top of their heads is easy to find, then by all means, ding candidates for their spelling during interviews. Thanks for making it that much easier for the rest of us to hire. In the industry I work in --- computer software --- it is ludicrously hard to find people competant in C programming, and I'm inclined to ignore idiosyncratic spelling in source code.
- djb_hackernews 16y agohmm, is it normal to assume all strings in C are \0 terminated? What are the memory usage implications for that? I won't pretend to know C but suppose you have a string that is 'ab{100}\0' and you wanted to remove all of the bs, you'd end up with 'a\0b{99}\0' in memory correct?
- RiderOfGiraffes 16y agoC works at a very low level. You have lumps of memory, and you can put stuff in it. By convention a "string" is actually a lump of memory with chars in it, and the end is indicated by a '\0'. The lump stays the same size and doesn't need tidying. This is the source of the notorious "fgets" bug/hack/exploit. This is not the time or place for a tutorial on C strings and memory management, but suffice to say that some people find it horrible, some people find it easy and obvious. It stems from C being a sort of macro-assembler with a simplistic type system glued on top of it. ADDED IN EDIT: I don't know why you got down-voted - it's a reasonable question from someone who hasn't done C. I've up-voted you to get you back to "1".
- tptacek 16y agofgets() bug/hack/exploit? You mean gets(), right?
- RiderOfGiraffes 16y agoEr, probably. Brain fried, too much multi-tasking. Sorry.
- js2 16y agoYes, C strings are \0 terminated and that is what you'd end up with. Memory management is between you, malloc() and free(). Assuming this were malloc()d memory, if you wanted to free up the unused bytes, you'd probably: char *condensed = strdup(z_terminated); if (condensed) free(z_terminated); else // out of memory
- 16y ago
- ydant 16y agoI haven't touched C in quite a number of years, so I was happy I got something working in pretty quick order that matched my initial brain-boarded algorithm. Years of Java apparently can't wash away C. As in the article, I started simple and condensed to the version that I actually submitted. In hindsight, I wonder if that is the best approach when answering an interview question via email. In person, there's obvious benefit to walking through optimization (of all sorts, including visual), but if all the other party sees is the final version, they lose out on that demonstration of the process. If you were to receive just the more condensed version from an interviewee, would that be a benefit or detriment to the person? Does it make sense to send an analysis, or is that just risking overwhelming the interviewer? I've asked for non-specific code samples in interviews before and that did serve to weed out an applicant once, but only because they sent on very easily searched for code (public API example code from a big developer). Asking for any sort of code example or coding example from an interviewer who isn't in the room always introduces the opportunity for cheating. Getting an analysis (I started here and ended up here) would probably help assuage my suspicions.
- leftnode 16y agoI'm nowhere near an experience C coder, but doesn't the in place part mean that you don't create any additional variables or strings and just modify z_terminated? Is that even possible? This is an honest question, because the solution is obvious this way, but a bit harder if you can't create additional variables.
- amalcon 16y ago"In-place" usually means "using only a constant amount of additional storage." You're using a constant amount of additional storage if you even use a function call (unless you're invoking certain compiler directives and/or optimizations), because C function calls usually involve placing a return address on the stack. This is also why quicksort is considered to take up log(n) space: it calls itself recursively, and thus uses up a bit of the stack for each recursive call.
- ydant 16y agoThe solution in the link only uses pointers to the string. "In place" as I understood it means not allocating additional memory for the string. His code does that, but it does need two pointers (the one passed in, and the one created to keep track of secondary position) in order to traverse the string. Because the resulting string will only be shorter (never longer), this works. You simply keep track of where you're copying to and where you're copying from, and move character by character until you reach the end. The resulting string may have extra stuff at the end, but since it's null terminated the standard C string functions will not see that cruft as they will stop at the first null.
- RiderOfGiraffes 16y ago"In place" usually means that the result is in the same place as the input, and you don't create an intermediate copy. Creating a fix, known number of additional variables to assist with the calculation is OK. Some people allocated memory, copied out the input, then put back the bits they wanted to keep. That is not "in place".
- Retric 16y ago
- loup-vaillant 16y agoAnd I thought my solution was as simple as possible. If only I decoupled my two increments, I may have avoided this unreadable, inefficient crap: void remove_char(char *s ,char c) { int from = -1; int to = -1; do { from++; to++; while (s[from] == c) from ++; s[to] = s[from]; } while (s[from] != '\0'); } Maybe that's why simplicity doesn't actually rule: it's hard to find. Or, people are silly (including myself in this case).
- jemfinch 16y agoYour code also fails (i.e., reads and writes past the end of the string) if c == '\0' and s is "\0".
- loup-vaillant 16y agoI considered the `c=='\0'` case bogus anyway, so I was OK with a partial function. (I wouldn't have been for production code, though.)
- RiderOfGiraffes 16y agoAre you saying that you actually considered that case, and then wrote code that didn't deal with it?
- loup-vaillant 16y agoYes I did, and then yes I did. I didn't fully investigated that case, but I suspected there could be a problem with `c=='\0'`. I suspected that the `while (s[from] == c) from ++;` line could shoot past the termination '\0' and trigger a buffer overflow. But I didn't fully investigate, on the grounds that no sane programmer would want to remove a character that's never in a C string. In other words, I considered it was not part of the specification. In production code, I would have either thrown an exception, or returned early. And I would have asked around to know which I would chose. Could my attitude have influenced my chances, if I had applied?
- pvdm 16y ago'\0' is null-terminated NOT zero-terminated, no ? By definition, a string in C is always null-terminated.
- cperciva 16y ago'\0' is a character, not a string. The string is "\0". Also, C strings are NUL-terminated, not NULL-terminated. (char)(0) is the NUL character; (void * )(0) is the NULL pointer (usually).
- avar 16y agoActually it's the NULL pointer by definition. 0 is always equivalent to NULL in pointer context, even though you're working with some hypothetical crazy system where NULL is actually #define NULL 1337. It's mandated by the standard. If (NULL == 0) isn't true you're not using C.
- cperciva 16y agoWhoops, I forgot the point I was trying to make. NULL is (void * )(0), but the code void * p; memset(&p, 0, sizeof(p)); assert(p == NULL); isn't necessarily valid, since the binary representation of NULL isn't necessarily as a sequence of zeroes -- even though everybody writes code which assumes that it is.
- avar 16y agoYeah, that's unportable. Although I'm not aware of any system where it doesn't work. For the record, regarding 0 in pointer context the C standard has this to say: An integral constant expression with the value 0, or such an expression cast to type void * , is called a null pointer constant. If a null pointer constant is assigned to or compared for equality to a pointer, the constant is converted to a pointer of that type. Such a pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function. -- C89/C90 section 3.2.2.3 Pointers The standard then goes on to say that NULL is a macro that's guaranteed to expand to a null pointer constant.
- cperciva 16y agoI'm sure RiderOfGiraffes doesn't want a third entry from me at this point, so I figure I might as well just post it here: #define C char #define F for #define R condense_by_removing #define V void V R(C*A,C B){F(C*J=A;*J=*A++;J+=*J!=B);} or without #defines: void condense_by_removing(char*A,char B){for(char*J=A;*J=*A++;J+=*J!=B);}
- RiderOfGiraffes 16y agoBy all means send it in - it will be interesting to compare it against the others.
- loup-vaillant 16y agoHere is the same code, without syntactic obfuscation: void condense_by_removing(char* s, char c) { char* d = s; while (*d = *s++) d += *d != c; } I would have sworn I found a bug. There is none. Brilliant. Now, I wonder if we could further optimize it. For instance by accessing memory several bytes at a time, in a fashion similar to strcmp().
- cperciva 16y agoOptimizing for performance, sure. But I was trying to optimize for character count. :-)
- loup-vaillant 16y agoYes, but in doing so, you traded a memory write for a branch. And memory accesses are linear, so that's likely faster than the cannon. So surely we could go further? That's how I got the idea.
- Daniel_Newby 16y agoMany compilers will implement d += *d != c; with a branch, and depending on the data pattern the branch predictor will be bamboozled. The branchless version would involve a pair of subtractions and some bit banging.
- gabeiscoding 16y agoI got this exact same question in a Google on-site interview. It was one of those warm-ups :) It does require someone to think like a C programmer: handling buffers directly, in-place modification and using NULL terminators to end strings that may have memory allocated beyond the NULL. I think it's a great question, but I don't know how well it would go over with CS undergrad students coming out with a Java only background. Should I look for an equivalent simplistic Java question or stick to the guns and require candidates to know C? (I know the answer for my own team, but curious on others thoughts)
- sram 16y agoI always end up using perl when I have to do string manipulations and have let my c skills suffer as a result. Sad. Using perl regexp kills brain cells. #!/usr/bin/perl $in = <STDIN>; $remove = <STDIN>; chomp ($remove); chomp ($in); $in =~ s/$remove//g;
- nevinera 16y agoBad boy! >hello|goodbye >| >>Result is 'hello|goodbye' >That's a nice dog you have there. >. >>Result is '' I usually handle this with: my $pattern = '\\'.substr($in,0,1); $in =~ s/$pattern//g; but it still doesn't feel safe. String operations in perl usually do what you want, but be careful with them!
- jerf 16y ago$in =~ s/\Q$remove\E//g; man perlre, search for \Q. When \Q and \E'ing a variable like that, a literal "\E" in the variable value can not escape from the outer \Q.
- deleted 16y ago[deleted]
- shabble 16y agoperl -pe'BEGIN { $x = quotemeta(shift) } s/$x//g;' should do what you want. `quotemeta' is the function that does the escaping for your properly. I was hoping to be able to use tr///, since it seems like it was built for this, but it creates its conversion tables at compile time, so there's no chance to interpolate the argument without some nasty nasty eval'ing.
- nevinera 16y agoYeah, tr was my instinct as well.. Thanks for quotemeta, it helps with something I'm working on right now!
- smackfu 16y agoNo, you have to do it in c so that there are all sorts of obscure bugs.
- deleted 16y ago[deleted]
- jemfinch 16y agoI wonder if I'm alone in thinking that the original `while` version is easier to read and understand than the ending `for` version. I've never quite understood C programmers' love of the `for` loop. It's just a `while` loop with the different parts stuck in different places (`init; while (cond) { ...; inc; }` is the same as `for(init; cond; inc) { ...; }`) and it doesn't (at least for me) result in any greater clarity or ease in reasoning.
- RiderOfGiraffes 16y agoActually, they are not the same. See the trivia question in the lunk article.
- jemfinch 16y agoI saw the trivia question in the link article, but it doesn't provide an answer, so I ignored it. EDIT: K&R says (page 60 in my second edition): """ The for statement for (expr1; expr2; expr3) statement is equivalent to expr1; while (expr2) { statement expr3; } except for the behavior of continue, which is described in Section 3.7. """ So apparently the trivia is the behavior of `continue`, which I think most C programmers (including myself) would know implicitly, even if we couldn't answer the question itself.
- RiderOfGiraffes 16y agoAnd it's because the knowledge is implicit and used when appropriate without thinking about it, that the question is, in my opinion, pointless as an interview question, except perhaps to see how the candidate reacts to it.
- edanm 16y agoI think for loops are better than while loops for looping over arrays. I'll try and explain my reasoning: Whenever you see a `for` loop, it tells you something that a `while` loop doesn't. It tells you the kind of loop you're about to do. A `for` (usually) means you're going to be looping over an array, with a specific length, with a specific "step" (usually one). This is information you immediately get by seeing a `for`. Moreover, you get all the information about how the loop looks (what you're looping over, size of the array, other actions you intend to perform in the loop) all in one place. This especially helps when you're looking at a large piece of code, in which case your example of "while (cond) {...;inc;}" would have a lot of lines between the condition and the increment.
- huherto 16y agoHis solution is so similar to mine that is scary. I also went thru the same optimization process. (e.g started with a while and changed that to a for later) I didn't go farther because I didn't want to loose readability. void condense_by_removing( char *z_terminated , char char_to_remove ) { char *rptr = z_terminated; // read ptr char *wptr = z_terminated; // write ptr for(;*rptr; rptr++) { if (*rptr != char_to_remove) { *wptr++ = *rptr; } } *wptr = 0; }
- petercooper 16y agoTurns out his solution is almost the same as mine except I skip the termination stage and instead read one character more in the loop which catches the \0 from the original end of the string automatically. As I'm not really a C programmer, was I doing something bad/unrecommended? It seemed to work.. :-)
- RiderOfGiraffes 16y agoDo you want to email me your reference number and I'll have a chat about it. It would be useful for me to clarify the next article on this point.
- zb 16y agoWhat happens if you pass '\0' as the character to remove?
- ydant 16y agoLike the grandparent, I do the same. I have the copy routine also copy over the final 0. If you pass in 0 as the character to remove, it still works fine. Nothing is shifted, so the final 0 is copied and the string remains null terminated. Technically this could be undesirable behavior (it's contrary to the spec), but I don't think the behavior if you do pass in a 0 to remove could be easily defined. What does it copy into the place where the null was? How does it know where to stop? Easier to just assume it's remove any non-null character and asking to remove null means remove nothing.
- logicalmind 16y agoYou can add a little twist to this test to make it slightly more difficult by changing the char to remove to be an array of char's to remove.
- anatoly 16y agoInteresting. I didn't try to do the assignment when I read the first part, but just tried it now before looking at the second part. When I started to write the main loop, I felt uneasy when I realized I'd be doing unnecessary copying in the common case when char_to_remove is never found. My code ended up a tad more complex than yours due to desire to avoid that: void condense_by_removing(char *z_terminated, char char_to_remove) { char *p = z_terminated; for (; *z_terminated != 0; ++z_terminated) { if (*z_terminated != char_to_remove) { if (z_terminated != p) *p = *z_terminated; p++; } } if (*p != 0) *p = 0; }
- dkersten 16y agoThis is what I came up with, but I'm not a C programmer. void condense_by_removing(char* z_terminated, char char_to_remove) { int index; int write = 0; for (index = 0; z_terminated[index]; ++index) { if (z_terminated[index + write] == char_to_remove) { ++write; } if (write > 0) { z_terminated[index] = z_terminated[index + write]; } } } Or, getting rid of index: void condense_by_removing(char* z_terminated, char char_to_remove) { int write = 0; for (; *z_terminated; ++z_terminated) { if (*(z_terminated + write) == char_to_remove) { ++write; } if (write > 0) { *z_terminated = *(z_terminated + write); } } }
- anatoly 16y agoI see what you're trying to do, but it won't work this way. Since your termination condition is z_terminated[index], you must never look beyond index, yet you access [index+write]. This alone means the code's buggy. The second version is similarly flawed. Note that your code instantly becomes much easier to understand if you rename the variable 'write' to 'gap'.
- dkersten 16y agoEhh, good point. :-/ The second version is identical to the first, except that it ises the z_terminated pointer instead of a separate index. void condense_by_removing(char* z_terminated, char char_to_remove) { int gap = 0; for (; *(z_terminated + gap); ++z_terminated) { if (*(z_terminated + gap) == char_to_remove) { ++gap; } if (gap > 0) { *z_terminated = *(z_terminated + gap); } } *z_terminated = 0; } Interestingly enough, if I try to remove the common *(z_terminated + gap) expression (which a good compiler should do for me..), I end up with a two pointer version similar to yours.
- rottencupcakes 16y agoSo, I've never been involved in hiring, so I have no perspective on the state of the job market. However, I have trouble believing that anyone who would be willing to rep themselves as a "C Developer" couldn't write this particular piece of code in a manner similar to the author's solution in a matter of minutes. Do these FizzBuzz articles keep getting promoted to the front page to boost everyone's collective egos, or is the job market really this pitiful? Can someone who has been involved in hiring recently comment with some anecdotal evidence as to what they've seen?
- wheaties 16y agoIt isn't that pitiful, per se, but there are a lot of people who want to be programmers trying to pass themselves off as actual programmers. Then again, there are a small handful of people who can't code that apply all over the place because no one will hire them. There's more of the unhireables than you'd think.
- smackfu 16y agoTo be honest, the people we hire tend to fall down in ways other than coding skills. Sloppiness in following procedures or pure laziness are much bigger impacts. Does anyone have a test for that?
- RiderOfGiraffes 16y agoI've been involved in hiring, I've seen it, it's true. There are people who have excellent CVs who cannot write this code.
- tptacek 16y agoThe problem isn't the job market --- although it is pitiful, and it is dreadfully hard to hire talented developers, particularly in C. The problem is that the hiring process is necessarily ineffective. You have a very short period of time to come to a sweeping conclusion about the entirety of someone's capabilities. Dev interviewers do a notoriously crappy job at this. The specific problem "FizzBuzz" tests solve is this: candidates who can talk about development (including people who know that the difference between otherwise equivalent for() and while() statements is whether the increment runs when you hit a "continue"), but who, when asked to sit down and code something, fumble horribly. These people, all of whom are smart and extremely knowledgeable about software development, have not developed the real world programming survival skill of being able to sit down and just code when they need to. Most development shops want to avoid these people. Hence: a test that isolates specifically your ability to just start coding, apart from any domain knowledge or computer science.
- bkz 16y agoFunny how readable Python is: def condense(s, remove): return "".join([c for c in s if c != remove]) Cheating (2.6+): s.translate(None, remove)
- JoachimSchipper 16y agoYou are aware that this is, to a C programmer, horribly inefficient? (Specifically, it violates the "in-place" requirement, but the actual overhead of that is dwarfed by everything else.)
- zepolen 16y agoEither you do it correctly (as in list manipulation, in place) or do it pythonically. That code is somewhere in between. The pythonic version would be s.replace(c, '')
- Vocalspace 16y agoSadly, the code YOU wrote is suboptimal. It doesn't check for bad pointers, has no comments, doesn't take memory corruption into consideration, and assumes the replacement character is not '\0'. You would get a C- if I graded your test. Now you'll argue that it's just a test, but the fact is your best work should not come only when under unexpected scrutiny, as it does with impromptu tests, it should be a mental process that is not bypassed for any reason. In this case you've thought about it for weeks and still botched it. Kudos for trying. We'll call you if we are interested.
- RiderOfGiraffes 16y agoInteresting - thank you for your feedback. It's educational to see the different points of view. However, I wonder if you've actually taken on board either the point of the exercise, or the fact that it isn't yet finished. However, questions such as those you raise are, of course, of great interest in production code, and would be raised in the discussion this code is intended to start. If someone started to write correct code that took these things into consideration the test would be stopped - it would've served its purpose already. I'd be interested to know: * Do you think every routine, every piece of code should have comments? * Do you think every routine should test its input parameters? Every time? * Do you think every routine should be checking for memory corruption? All the time? * How do you cope with memory corruption in the program code itself? * Do you think the routine fails if the char to remove is '\0'? Are you sure? You seem to claim it does. * Do you believe that all code should always be written to the same standard? Having written code in an environment where any given memory location has a MTC (Mean Time to Corruption) of 12 hours, I have considered these issues. I'd be interested to hear your experiences in these matters. I notice also that you created your username specifically to reply to this item. Welcome to Hacker News.
- cperciva 16y agoIt doesn't check for bad pointers C is a foot-shooting language. Its basic library functions are expected to do what you tell them to do, even when it's a really bad idea. Checking for bad pointers (and how exactly you define "bad" is a rather interesting question) is clearly out of scope. has no comments True, but I'm not convinced there's much point on such a trivial piece of code. doesn't take memory corruption into consideration Given that there is no redundant information available, this is an impossible challenge. and assumes the replacement character is not '\0'. Try re-reading the code a bit more closely.
- Enlightenment 16y agowhile(1) Write_Code();
- deleted 16y ago[deleted]
- rayval 16y agoComing late to the party, here is my version. Even though it uses some weird constructs, it compiles and runs with TurboC V2.01 from 1988: char *d,*s; for(d = s = z_terminated; *s; s += (char_to_remove== *s)?1:((*d++ = *s++),0)) {;} *d = *s; Note this is the "fun version". For production code, I would use more conventional constructs, rather than the comma-delimited embedded expression with side effects.
- RiderOfGiraffes 16y agoTaster of the analysis to come: http://news.ycombinator.com/item?id=1404347 http://news.ycombinator.com/item?id=1404347
- chrisbuchino 16y agoI have hired (and fired) a lot of software developers and cannot stress enough the importance of having candidates write code up-front. Having made poor hiring decisions myself by not doing this well and having "inherited" team members who whose coding skills left something to be desired, I would argue that few things are as crippling to an organization as bad programmers. Someone can be the nicest person ever, but if they don't write code well - they will cost you in time, money, and unnecessary technical debt. I don't agree that FizzBuzz tests are the ways to screen developers though. These types of questions may give insight into IQ but I've seen really bright people be really sloppy coders. The way the problem is solved is just as important as getting the problem right and making it fast. If it isn't readable, you better hope that person does not get hit by a bus because if you need to modify it later, you're in trouble.